diff options
Diffstat (limited to 'sound/pci')
72 files changed, 20094 insertions, 1613 deletions
diff --git a/sound/pci/Kconfig b/sound/pci/Kconfig index 93422e3a3f0c..748f6b7d90b7 100644 --- a/sound/pci/Kconfig +++ b/sound/pci/Kconfig | |||
@@ -275,6 +275,16 @@ config SND_CS5535AUDIO | |||
275 | To compile this driver as a module, choose M here: the module | 275 | To compile this driver as a module, choose M here: the module |
276 | will be called snd-cs5535audio. | 276 | will be called snd-cs5535audio. |
277 | 277 | ||
278 | config SND_CTXFI | ||
279 | tristate "Creative Sound Blaster X-Fi" | ||
280 | select SND_PCM | ||
281 | help | ||
282 | If you want to use soundcards based on Creative Sound Blastr X-Fi | ||
283 | boards with 20k1 or 20k2 chips, say Y here. | ||
284 | |||
285 | To compile this driver as a module, choose M here: the module | ||
286 | will be called snd-ctxfi. | ||
287 | |||
278 | config SND_DARLA20 | 288 | config SND_DARLA20 |
279 | tristate "(Echoaudio) Darla20" | 289 | tristate "(Echoaudio) Darla20" |
280 | select FW_LOADER | 290 | select FW_LOADER |
@@ -532,6 +542,9 @@ config SND_HDSP | |||
532 | To compile this driver as a module, choose M here: the module | 542 | To compile this driver as a module, choose M here: the module |
533 | will be called snd-hdsp. | 543 | will be called snd-hdsp. |
534 | 544 | ||
545 | comment "Don't forget to add built-in firmwares for HDSP driver" | ||
546 | depends on SND_HDSP=y | ||
547 | |||
535 | config SND_HDSPM | 548 | config SND_HDSPM |
536 | tristate "RME Hammerfall DSP MADI" | 549 | tristate "RME Hammerfall DSP MADI" |
537 | select SND_HWDEP | 550 | select SND_HWDEP |
@@ -622,6 +635,16 @@ config SND_KORG1212 | |||
622 | To compile this driver as a module, choose M here: the module | 635 | To compile this driver as a module, choose M here: the module |
623 | will be called snd-korg1212. | 636 | will be called snd-korg1212. |
624 | 637 | ||
638 | config SND_LX6464ES | ||
639 | tristate "Digigram LX6464ES" | ||
640 | select SND_PCM | ||
641 | help | ||
642 | Say Y here to include support for Digigram LX6464ES boards. | ||
643 | |||
644 | To compile this driver as a module, choose M here: the module | ||
645 | will be called snd-lx6464es. | ||
646 | |||
647 | |||
625 | config SND_MAESTRO3 | 648 | config SND_MAESTRO3 |
626 | tristate "ESS Allegro/Maestro3" | 649 | tristate "ESS Allegro/Maestro3" |
627 | select SND_AC97_CODEC | 650 | select SND_AC97_CODEC |
@@ -764,8 +787,8 @@ config SND_VIRTUOSO | |||
764 | select SND_OXYGEN_LIB | 787 | select SND_OXYGEN_LIB |
765 | help | 788 | help |
766 | Say Y here to include support for sound cards based on the | 789 | Say Y here to include support for sound cards based on the |
767 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, and | 790 | Asus AV100/AV200 chips, i.e., Xonar D1, DX, D2, D2X, |
768 | Essence STX. | 791 | Essence ST (Deluxe), and Essence STX. |
769 | Support for the HDAV1.3 (Deluxe) is very experimental. | 792 | Support for the HDAV1.3 (Deluxe) is very experimental. |
770 | 793 | ||
771 | To compile this driver as a module, choose M here: the module | 794 | To compile this driver as a module, choose M here: the module |
diff --git a/sound/pci/Makefile b/sound/pci/Makefile index 65b25d221cd2..ecfc609d2b9f 100644 --- a/sound/pci/Makefile +++ b/sound/pci/Makefile | |||
@@ -59,9 +59,11 @@ obj-$(CONFIG_SND) += \ | |||
59 | ali5451/ \ | 59 | ali5451/ \ |
60 | au88x0/ \ | 60 | au88x0/ \ |
61 | aw2/ \ | 61 | aw2/ \ |
62 | ctxfi/ \ | ||
62 | ca0106/ \ | 63 | ca0106/ \ |
63 | cs46xx/ \ | 64 | cs46xx/ \ |
64 | cs5535audio/ \ | 65 | cs5535audio/ \ |
66 | lx6464es/ \ | ||
65 | echoaudio/ \ | 67 | echoaudio/ \ |
66 | emu10k1/ \ | 68 | emu10k1/ \ |
67 | hda/ \ | 69 | hda/ \ |
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c index 81bc93e5f1e3..7337abdbe4e3 100644 --- a/sound/pci/ac97/ac97_patch.c +++ b/sound/pci/ac97/ac97_patch.c | |||
@@ -958,10 +958,13 @@ static int patch_sigmatel_stac9708_3d(struct snd_ac97 * ac97) | |||
958 | } | 958 | } |
959 | 959 | ||
960 | static const struct snd_kcontrol_new snd_ac97_sigmatel_4speaker = | 960 | static const struct snd_kcontrol_new snd_ac97_sigmatel_4speaker = |
961 | AC97_SINGLE("Sigmatel 4-Speaker Stereo Playback Switch", AC97_SIGMATEL_DAC2INVERT, 2, 1, 0); | 961 | AC97_SINGLE("Sigmatel 4-Speaker Stereo Playback Switch", |
962 | AC97_SIGMATEL_DAC2INVERT, 2, 1, 0); | ||
962 | 963 | ||
964 | /* "Sigmatel " removed due to excessive name length: */ | ||
963 | static const struct snd_kcontrol_new snd_ac97_sigmatel_phaseinvert = | 965 | static const struct snd_kcontrol_new snd_ac97_sigmatel_phaseinvert = |
964 | AC97_SINGLE("Sigmatel Surround Phase Inversion Playback Switch", AC97_SIGMATEL_DAC2INVERT, 3, 1, 0); | 966 | AC97_SINGLE("Surround Phase Inversion Playback Switch", |
967 | AC97_SIGMATEL_DAC2INVERT, 3, 1, 0); | ||
965 | 968 | ||
966 | static const struct snd_kcontrol_new snd_ac97_sigmatel_controls[] = { | 969 | static const struct snd_kcontrol_new snd_ac97_sigmatel_controls[] = { |
967 | AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0), | 970 | AC97_SINGLE("Sigmatel DAC 6dB Attenuate", AC97_SIGMATEL_ANALOG, 1, 1, 0), |
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c index 3906f5afe27a..23f49f356e0f 100644 --- a/sound/pci/au88x0/au88x0_core.c +++ b/sound/pci/au88x0/au88x0_core.c | |||
@@ -1255,8 +1255,8 @@ static int inline vortex_adbdma_getlinearpos(vortex_t * vortex, int adbdma) | |||
1255 | int temp; | 1255 | int temp; |
1256 | 1256 | ||
1257 | temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)); | 1257 | temp = hwread(vortex->mmio, VORTEX_ADBDMA_STAT + (adbdma << 2)); |
1258 | temp = (dma->period_virt * dma->period_bytes) + (temp & POS_MASK); | 1258 | temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1)); |
1259 | return (temp); | 1259 | return temp; |
1260 | } | 1260 | } |
1261 | 1261 | ||
1262 | static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma) | 1262 | static void vortex_adbdma_startfifo(vortex_t * vortex, int adbdma) |
@@ -1504,8 +1504,7 @@ static int inline vortex_wtdma_getlinearpos(vortex_t * vortex, int wtdma) | |||
1504 | int temp; | 1504 | int temp; |
1505 | 1505 | ||
1506 | temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)); | 1506 | temp = hwread(vortex->mmio, VORTEX_WTDMA_STAT + (wtdma << 2)); |
1507 | //temp = (temp & POS_MASK) + (((temp>>WT_SUBBUF_SHIFT) & WT_SUBBUF_MASK)*(dma->cfg0&POS_MASK)); | 1507 | temp = (dma->period_virt * dma->period_bytes) + (temp & (dma->period_bytes - 1)); |
1508 | temp = (temp & POS_MASK) + ((dma->period_virt) * (dma->period_bytes)); | ||
1509 | return temp; | 1508 | return temp; |
1510 | } | 1509 | } |
1511 | 1510 | ||
@@ -2441,7 +2440,8 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id) | |||
2441 | spin_lock(&vortex->lock); | 2440 | spin_lock(&vortex->lock); |
2442 | for (i = 0; i < NR_ADB; i++) { | 2441 | for (i = 0; i < NR_ADB; i++) { |
2443 | if (vortex->dma_adb[i].fifo_status == FIFO_START) { | 2442 | if (vortex->dma_adb[i].fifo_status == FIFO_START) { |
2444 | if (vortex_adbdma_bufshift(vortex, i)) ; | 2443 | if (!vortex_adbdma_bufshift(vortex, i)) |
2444 | continue; | ||
2445 | spin_unlock(&vortex->lock); | 2445 | spin_unlock(&vortex->lock); |
2446 | snd_pcm_period_elapsed(vortex->dma_adb[i]. | 2446 | snd_pcm_period_elapsed(vortex->dma_adb[i]. |
2447 | substream); | 2447 | substream); |
diff --git a/sound/pci/bt87x.c b/sound/pci/bt87x.c index ce3f2e90f4d7..24585c6c6d01 100644 --- a/sound/pci/bt87x.c +++ b/sound/pci/bt87x.c | |||
@@ -810,6 +810,8 @@ static struct pci_device_id snd_bt87x_ids[] = { | |||
810 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC), | 810 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x107d, 0x6606, GENERIC), |
811 | /* Voodoo TV 200 */ | 811 | /* Voodoo TV 200 */ |
812 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC), | 812 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x121a, 0x3000, GENERIC), |
813 | /* Askey Computer Corp. MagicTView'99 */ | ||
814 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x144f, 0x3000, GENERIC), | ||
813 | /* AVerMedia Studio No. 103, 203, ...? */ | 815 | /* AVerMedia Studio No. 103, 203, ...? */ |
814 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98), | 816 | BT_DEVICE(PCI_DEVICE_ID_BROOKTREE_878, 0x1461, 0x0003, AVPHONE98), |
815 | /* Prolink PixelView PV-M4900 */ | 817 | /* Prolink PixelView PV-M4900 */ |
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index bfac30f7929f..57b992a5c057 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -1319,7 +1319,6 @@ static int __devinit snd_ca0106_pcm(struct snd_ca0106 *emu, int device) | |||
1319 | } | 1319 | } |
1320 | 1320 | ||
1321 | pcm->info_flags = 0; | 1321 | pcm->info_flags = 0; |
1322 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | ||
1323 | strcpy(pcm->name, "CA0106"); | 1322 | strcpy(pcm->name, "CA0106"); |
1324 | 1323 | ||
1325 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; | 1324 | for(substream = pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream; |
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c index ad2888705d2a..c8c6f437f5b3 100644 --- a/sound/pci/ca0106/ca0106_mixer.c +++ b/sound/pci/ca0106/ca0106_mixer.c | |||
@@ -739,7 +739,7 @@ static int __devinit rename_ctl(struct snd_card *card, const char *src, const ch | |||
739 | } while (0) | 739 | } while (0) |
740 | 740 | ||
741 | static __devinitdata | 741 | static __devinitdata |
742 | DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 50, 1); | 742 | DECLARE_TLV_DB_SCALE(snd_ca0106_master_db_scale, -6375, 25, 1); |
743 | 743 | ||
744 | static char *slave_vols[] __devinitdata = { | 744 | static char *slave_vols[] __devinitdata = { |
745 | "Analog Front Playback Volume", | 745 | "Analog Front Playback Volume", |
@@ -800,7 +800,7 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
800 | "Capture Volume", | 800 | "Capture Volume", |
801 | "External Amplifier", | 801 | "External Amplifier", |
802 | "Sigmatel 4-Speaker Stereo Playback Switch", | 802 | "Sigmatel 4-Speaker Stereo Playback Switch", |
803 | "Sigmatel Surround Phase Inversion Playback ", | 803 | "Surround Phase Inversion Playback Switch", |
804 | NULL | 804 | NULL |
805 | }; | 805 | }; |
806 | static char *ca0106_rename_ctls[] = { | 806 | static char *ca0106_rename_ctls[] = { |
@@ -841,6 +841,9 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
841 | snd_ca0106_master_db_scale); | 841 | snd_ca0106_master_db_scale); |
842 | if (!vmaster) | 842 | if (!vmaster) |
843 | return -ENOMEM; | 843 | return -ENOMEM; |
844 | err = snd_ctl_add(card, vmaster); | ||
845 | if (err < 0) | ||
846 | return err; | ||
844 | add_slaves(card, vmaster, slave_vols); | 847 | add_slaves(card, vmaster, slave_vols); |
845 | 848 | ||
846 | if (emu->details->spi_dac == 1) { | 849 | if (emu->details->spi_dac == 1) { |
@@ -848,8 +851,13 @@ int __devinit snd_ca0106_mixer(struct snd_ca0106 *emu) | |||
848 | NULL); | 851 | NULL); |
849 | if (!vmaster) | 852 | if (!vmaster) |
850 | return -ENOMEM; | 853 | return -ENOMEM; |
854 | err = snd_ctl_add(card, vmaster); | ||
855 | if (err < 0) | ||
856 | return err; | ||
851 | add_slaves(card, vmaster, slave_sws); | 857 | add_slaves(card, vmaster, slave_sws); |
852 | } | 858 | } |
859 | |||
860 | strcpy(card->mixername, "CA0106"); | ||
853 | return 0; | 861 | return 0; |
854 | } | 862 | } |
855 | 863 | ||
diff --git a/sound/pci/ctxfi/Makefile b/sound/pci/ctxfi/Makefile new file mode 100644 index 000000000000..15075f89e98a --- /dev/null +++ b/sound/pci/ctxfi/Makefile | |||
@@ -0,0 +1,5 @@ | |||
1 | snd-ctxfi-objs := xfi.o ctatc.o ctvmem.o ctpcm.o ctmixer.o ctresource.o \ | ||
2 | ctsrc.o ctamixer.o ctdaio.o ctimap.o cthardware.o cttimer.o \ | ||
3 | cthw20k2.o cthw20k1.o | ||
4 | |||
5 | obj-$(CONFIG_SND_CTXFI) += snd-ctxfi.o | ||
diff --git a/sound/pci/ctxfi/ct20k1reg.h b/sound/pci/ctxfi/ct20k1reg.h new file mode 100644 index 000000000000..f2e34e3f27ee --- /dev/null +++ b/sound/pci/ctxfi/ct20k1reg.h | |||
@@ -0,0 +1,636 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | */ | ||
8 | |||
9 | #ifndef CT20K1REG_H | ||
10 | #define CT20k1REG_H | ||
11 | |||
12 | /* 20k1 registers */ | ||
13 | #define DSPXRAM_START 0x000000 | ||
14 | #define DSPXRAM_END 0x013FFC | ||
15 | #define DSPAXRAM_START 0x020000 | ||
16 | #define DSPAXRAM_END 0x023FFC | ||
17 | #define DSPYRAM_START 0x040000 | ||
18 | #define DSPYRAM_END 0x04FFFC | ||
19 | #define DSPAYRAM_START 0x020000 | ||
20 | #define DSPAYRAM_END 0x063FFC | ||
21 | #define DSPMICRO_START 0x080000 | ||
22 | #define DSPMICRO_END 0x0B3FFC | ||
23 | #define DSP0IO_START 0x100000 | ||
24 | #define DSP0IO_END 0x101FFC | ||
25 | #define AUDIORINGIPDSP0_START 0x100000 | ||
26 | #define AUDIORINGIPDSP0_END 0x1003FC | ||
27 | #define AUDIORINGOPDSP0_START 0x100400 | ||
28 | #define AUDIORINGOPDSP0_END 0x1007FC | ||
29 | #define AUDPARARINGIODSP0_START 0x100800 | ||
30 | #define AUDPARARINGIODSP0_END 0x100BFC | ||
31 | #define DSP0LOCALHWREG_START 0x100C00 | ||
32 | #define DSP0LOCALHWREG_END 0x100C3C | ||
33 | #define DSP0XYRAMAGINDEX_START 0x100C40 | ||
34 | #define DSP0XYRAMAGINDEX_END 0x100C5C | ||
35 | #define DSP0XYRAMAGMDFR_START 0x100C60 | ||
36 | #define DSP0XYRAMAGMDFR_END 0x100C7C | ||
37 | #define DSP0INTCONTLVEC_START 0x100C80 | ||
38 | #define DSP0INTCONTLVEC_END 0x100CD8 | ||
39 | #define INTCONTLGLOBALREG_START 0x100D1C | ||
40 | #define INTCONTLGLOBALREG_END 0x100D3C | ||
41 | #define HOSTINTFPORTADDRCONTDSP0 0x100D40 | ||
42 | #define HOSTINTFPORTDATADSP0 0x100D44 | ||
43 | #define TIME0PERENBDSP0 0x100D60 | ||
44 | #define TIME0COUNTERDSP0 0x100D64 | ||
45 | #define TIME1PERENBDSP0 0x100D68 | ||
46 | #define TIME1COUNTERDSP0 0x100D6C | ||
47 | #define TIME2PERENBDSP0 0x100D70 | ||
48 | #define TIME2COUNTERDSP0 0x100D74 | ||
49 | #define TIME3PERENBDSP0 0x100D78 | ||
50 | #define TIME3COUNTERDSP0 0x100D7C | ||
51 | #define XRAMINDOPERREFNOUP_STARTDSP0 0x100D80 | ||
52 | #define XRAMINDOPERREFNOUP_ENDDSP0 0x100D9C | ||
53 | #define XRAMINDOPERREFUP_STARTDSP0 0x100DA0 | ||
54 | #define XRAMINDOPERREFUP_ENDDSP0 0x100DBC | ||
55 | #define YRAMINDOPERREFNOUP_STARTDSP0 0x100DC0 | ||
56 | #define YRAMINDOPERREFNOUP_ENDDSP0 0x100DDC | ||
57 | #define YRAMINDOPERREFUP_STARTDSP0 0x100DE0 | ||
58 | #define YRAMINDOPERREFUP_ENDDSP0 0x100DFC | ||
59 | #define DSP0CONDCODE 0x100E00 | ||
60 | #define DSP0STACKFLAG 0x100E04 | ||
61 | #define DSP0PROGCOUNTSTACKPTREG 0x100E08 | ||
62 | #define DSP0PROGCOUNTSTACKDATAREG 0x100E0C | ||
63 | #define DSP0CURLOOPADDRREG 0x100E10 | ||
64 | #define DSP0CURLOOPCOUNT 0x100E14 | ||
65 | #define DSP0TOPLOOPCOUNTSTACK 0x100E18 | ||
66 | #define DSP0TOPLOOPADDRSTACK 0x100E1C | ||
67 | #define DSP0LOOPSTACKPTR 0x100E20 | ||
68 | #define DSP0STASSTACKDATAREG 0x100E24 | ||
69 | #define DSP0STASSTACKPTR 0x100E28 | ||
70 | #define DSP0PROGCOUNT 0x100E2C | ||
71 | #define GLOBDSPDEBGREG 0x100E30 | ||
72 | #define GLOBDSPBREPTRREG 0x100E30 | ||
73 | #define DSP0XYRAMBASE_START 0x100EA0 | ||
74 | #define DSP0XYRAMBASE_END 0x100EBC | ||
75 | #define DSP0XYRAMLENG_START 0x100EC0 | ||
76 | #define DSP0XYRAMLENG_END 0x100EDC | ||
77 | #define SEMAPHOREREGDSP0 0x100EE0 | ||
78 | #define DSP0INTCONTMASKREG 0x100EE4 | ||
79 | #define DSP0INTCONTPENDREG 0x100EE8 | ||
80 | #define DSP0INTCONTSERVINT 0x100EEC | ||
81 | #define DSPINTCONTEXTINTMODREG 0x100EEC | ||
82 | #define GPIODSP0 0x100EFC | ||
83 | #define DMADSPBASEADDRREG_STARTDSP0 0x100F00 | ||
84 | #define DMADSPBASEADDRREG_ENDDSP0 0x100F1C | ||
85 | #define DMAHOSTBASEADDRREG_STARTDSP0 0x100F20 | ||
86 | #define DMAHOSTBASEADDRREG_ENDDSP0 0x100F3C | ||
87 | #define DMADSPCURADDRREG_STARTDSP0 0x100F40 | ||
88 | #define DMADSPCURADDRREG_ENDDSP0 0x100F5C | ||
89 | #define DMAHOSTCURADDRREG_STARTDSP0 0x100F60 | ||
90 | #define DMAHOSTCURADDRREG_ENDDSP0 0x100F7C | ||
91 | #define DMATANXCOUNTREG_STARTDSP0 0x100F80 | ||
92 | #define DMATANXCOUNTREG_ENDDSP0 0x100F9C | ||
93 | #define DMATIMEBUGREG_STARTDSP0 0x100FA0 | ||
94 | #define DMATIMEBUGREG_ENDDSP0 0x100FAC | ||
95 | #define DMACNTLMODFREG_STARTDSP0 0x100FA0 | ||
96 | #define DMACNTLMODFREG_ENDDSP0 0x100FAC | ||
97 | |||
98 | #define DMAGLOBSTATSREGDSP0 0x100FEC | ||
99 | #define DSP0XGPRAM_START 0x101000 | ||
100 | #define DSP0XGPRAM_END 0x1017FC | ||
101 | #define DSP0YGPRAM_START 0x101800 | ||
102 | #define DSP0YGPRAM_END 0x101FFC | ||
103 | |||
104 | |||
105 | |||
106 | |||
107 | #define AUDIORINGIPDSP1_START 0x102000 | ||
108 | #define AUDIORINGIPDSP1_END 0x1023FC | ||
109 | #define AUDIORINGOPDSP1_START 0x102400 | ||
110 | #define AUDIORINGOPDSP1_END 0x1027FC | ||
111 | #define AUDPARARINGIODSP1_START 0x102800 | ||
112 | #define AUDPARARINGIODSP1_END 0x102BFC | ||
113 | #define DSP1LOCALHWREG_START 0x102C00 | ||
114 | #define DSP1LOCALHWREG_END 0x102C3C | ||
115 | #define DSP1XYRAMAGINDEX_START 0x102C40 | ||
116 | #define DSP1XYRAMAGINDEX_END 0x102C5C | ||
117 | #define DSP1XYRAMAGMDFR_START 0x102C60 | ||
118 | #define DSP1XYRAMAGMDFR_END 0x102C7C | ||
119 | #define DSP1INTCONTLVEC_START 0x102C80 | ||
120 | #define DSP1INTCONTLVEC_END 0x102CD8 | ||
121 | #define HOSTINTFPORTADDRCONTDSP1 0x102D40 | ||
122 | #define HOSTINTFPORTDATADSP1 0x102D44 | ||
123 | #define TIME0PERENBDSP1 0x102D60 | ||
124 | #define TIME0COUNTERDSP1 0x102D64 | ||
125 | #define TIME1PERENBDSP1 0x102D68 | ||
126 | #define TIME1COUNTERDSP1 0x102D6C | ||
127 | #define TIME2PERENBDSP1 0x102D70 | ||
128 | #define TIME2COUNTERDSP1 0x102D74 | ||
129 | #define TIME3PERENBDSP1 0x102D78 | ||
130 | #define TIME3COUNTERDSP1 0x102D7C | ||
131 | #define XRAMINDOPERREFNOUP_STARTDSP1 0x102D80 | ||
132 | #define XRAMINDOPERREFNOUP_ENDDSP1 0x102D9C | ||
133 | #define XRAMINDOPERREFUP_STARTDSP1 0x102DA0 | ||
134 | #define XRAMINDOPERREFUP_ENDDSP1 0x102DBC | ||
135 | #define YRAMINDOPERREFNOUP_STARTDSP1 0x102DC0 | ||
136 | #define YRAMINDOPERREFNOUP_ENDDSP1 0x102DDC | ||
137 | #define YRAMINDOPERREFUP_STARTDSP1 0x102DE0 | ||
138 | #define YRAMINDOPERREFUP_ENDDSP1 0x102DFC | ||
139 | |||
140 | #define DSP1CONDCODE 0x102E00 | ||
141 | #define DSP1STACKFLAG 0x102E04 | ||
142 | #define DSP1PROGCOUNTSTACKPTREG 0x102E08 | ||
143 | #define DSP1PROGCOUNTSTACKDATAREG 0x102E0C | ||
144 | #define DSP1CURLOOPADDRREG 0x102E10 | ||
145 | #define DSP1CURLOOPCOUNT 0x102E14 | ||
146 | #define DSP1TOPLOOPCOUNTSTACK 0x102E18 | ||
147 | #define DSP1TOPLOOPADDRSTACK 0x102E1C | ||
148 | #define DSP1LOOPSTACKPTR 0x102E20 | ||
149 | #define DSP1STASSTACKDATAREG 0x102E24 | ||
150 | #define DSP1STASSTACKPTR 0x102E28 | ||
151 | #define DSP1PROGCOUNT 0x102E2C | ||
152 | #define DSP1XYRAMBASE_START 0x102EA0 | ||
153 | #define DSP1XYRAMBASE_END 0x102EBC | ||
154 | #define DSP1XYRAMLENG_START 0x102EC0 | ||
155 | #define DSP1XYRAMLENG_END 0x102EDC | ||
156 | #define SEMAPHOREREGDSP1 0x102EE0 | ||
157 | #define DSP1INTCONTMASKREG 0x102EE4 | ||
158 | #define DSP1INTCONTPENDREG 0x102EE8 | ||
159 | #define DSP1INTCONTSERVINT 0x102EEC | ||
160 | #define GPIODSP1 0x102EFC | ||
161 | #define DMADSPBASEADDRREG_STARTDSP1 0x102F00 | ||
162 | #define DMADSPBASEADDRREG_ENDDSP1 0x102F1C | ||
163 | #define DMAHOSTBASEADDRREG_STARTDSP1 0x102F20 | ||
164 | #define DMAHOSTBASEADDRREG_ENDDSP1 0x102F3C | ||
165 | #define DMADSPCURADDRREG_STARTDSP1 0x102F40 | ||
166 | #define DMADSPCURADDRREG_ENDDSP1 0x102F5C | ||
167 | #define DMAHOSTCURADDRREG_STARTDSP1 0x102F60 | ||
168 | #define DMAHOSTCURADDRREG_ENDDSP1 0x102F7C | ||
169 | #define DMATANXCOUNTREG_STARTDSP1 0x102F80 | ||
170 | #define DMATANXCOUNTREG_ENDDSP1 0x102F9C | ||
171 | #define DMATIMEBUGREG_STARTDSP1 0x102FA0 | ||
172 | #define DMATIMEBUGREG_ENDDSP1 0x102FAC | ||
173 | #define DMACNTLMODFREG_STARTDSP1 0x102FA0 | ||
174 | #define DMACNTLMODFREG_ENDDSP1 0x102FAC | ||
175 | |||
176 | #define DMAGLOBSTATSREGDSP1 0x102FEC | ||
177 | #define DSP1XGPRAM_START 0x103000 | ||
178 | #define DSP1XGPRAM_END 0x1033FC | ||
179 | #define DSP1YGPRAM_START 0x103400 | ||
180 | #define DSP1YGPRAM_END 0x1037FC | ||
181 | |||
182 | |||
183 | |||
184 | #define AUDIORINGIPDSP2_START 0x104000 | ||
185 | #define AUDIORINGIPDSP2_END 0x1043FC | ||
186 | #define AUDIORINGOPDSP2_START 0x104400 | ||
187 | #define AUDIORINGOPDSP2_END 0x1047FC | ||
188 | #define AUDPARARINGIODSP2_START 0x104800 | ||
189 | #define AUDPARARINGIODSP2_END 0x104BFC | ||
190 | #define DSP2LOCALHWREG_START 0x104C00 | ||
191 | #define DSP2LOCALHWREG_END 0x104C3C | ||
192 | #define DSP2XYRAMAGINDEX_START 0x104C40 | ||
193 | #define DSP2XYRAMAGINDEX_END 0x104C5C | ||
194 | #define DSP2XYRAMAGMDFR_START 0x104C60 | ||
195 | #define DSP2XYRAMAGMDFR_END 0x104C7C | ||
196 | #define DSP2INTCONTLVEC_START 0x104C80 | ||
197 | #define DSP2INTCONTLVEC_END 0x104CD8 | ||
198 | #define HOSTINTFPORTADDRCONTDSP2 0x104D40 | ||
199 | #define HOSTINTFPORTDATADSP2 0x104D44 | ||
200 | #define TIME0PERENBDSP2 0x104D60 | ||
201 | #define TIME0COUNTERDSP2 0x104D64 | ||
202 | #define TIME1PERENBDSP2 0x104D68 | ||
203 | #define TIME1COUNTERDSP2 0x104D6C | ||
204 | #define TIME2PERENBDSP2 0x104D70 | ||
205 | #define TIME2COUNTERDSP2 0x104D74 | ||
206 | #define TIME3PERENBDSP2 0x104D78 | ||
207 | #define TIME3COUNTERDSP2 0x104D7C | ||
208 | #define XRAMINDOPERREFNOUP_STARTDSP2 0x104D80 | ||
209 | #define XRAMINDOPERREFNOUP_ENDDSP2 0x104D9C | ||
210 | #define XRAMINDOPERREFUP_STARTDSP2 0x104DA0 | ||
211 | #define XRAMINDOPERREFUP_ENDDSP2 0x104DBC | ||
212 | #define YRAMINDOPERREFNOUP_STARTDSP2 0x104DC0 | ||
213 | #define YRAMINDOPERREFNOUP_ENDDSP2 0x104DDC | ||
214 | #define YRAMINDOPERREFUP_STARTDSP2 0x104DE0 | ||
215 | #define YRAMINDOPERREFUP_ENDDSP2 0x104DFC | ||
216 | #define DSP2CONDCODE 0x104E00 | ||
217 | #define DSP2STACKFLAG 0x104E04 | ||
218 | #define DSP2PROGCOUNTSTACKPTREG 0x104E08 | ||
219 | #define DSP2PROGCOUNTSTACKDATAREG 0x104E0C | ||
220 | #define DSP2CURLOOPADDRREG 0x104E10 | ||
221 | #define DSP2CURLOOPCOUNT 0x104E14 | ||
222 | #define DSP2TOPLOOPCOUNTSTACK 0x104E18 | ||
223 | #define DSP2TOPLOOPADDRSTACK 0x104E1C | ||
224 | #define DSP2LOOPSTACKPTR 0x104E20 | ||
225 | #define DSP2STASSTACKDATAREG 0x104E24 | ||
226 | #define DSP2STASSTACKPTR 0x104E28 | ||
227 | #define DSP2PROGCOUNT 0x104E2C | ||
228 | #define DSP2XYRAMBASE_START 0x104EA0 | ||
229 | #define DSP2XYRAMBASE_END 0x104EBC | ||
230 | #define DSP2XYRAMLENG_START 0x104EC0 | ||
231 | #define DSP2XYRAMLENG_END 0x104EDC | ||
232 | #define SEMAPHOREREGDSP2 0x104EE0 | ||
233 | #define DSP2INTCONTMASKREG 0x104EE4 | ||
234 | #define DSP2INTCONTPENDREG 0x104EE8 | ||
235 | #define DSP2INTCONTSERVINT 0x104EEC | ||
236 | #define GPIODSP2 0x104EFC | ||
237 | #define DMADSPBASEADDRREG_STARTDSP2 0x104F00 | ||
238 | #define DMADSPBASEADDRREG_ENDDSP2 0x104F1C | ||
239 | #define DMAHOSTBASEADDRREG_STARTDSP2 0x104F20 | ||
240 | #define DMAHOSTBASEADDRREG_ENDDSP2 0x104F3C | ||
241 | #define DMADSPCURADDRREG_STARTDSP2 0x104F40 | ||
242 | #define DMADSPCURADDRREG_ENDDSP2 0x104F5C | ||
243 | #define DMAHOSTCURADDRREG_STARTDSP2 0x104F60 | ||
244 | #define DMAHOSTCURADDRREG_ENDDSP2 0x104F7C | ||
245 | #define DMATANXCOUNTREG_STARTDSP2 0x104F80 | ||
246 | #define DMATANXCOUNTREG_ENDDSP2 0x104F9C | ||
247 | #define DMATIMEBUGREG_STARTDSP2 0x104FA0 | ||
248 | #define DMATIMEBUGREG_ENDDSP2 0x104FAC | ||
249 | #define DMACNTLMODFREG_STARTDSP2 0x104FA0 | ||
250 | #define DMACNTLMODFREG_ENDDSP2 0x104FAC | ||
251 | |||
252 | #define DMAGLOBSTATSREGDSP2 0x104FEC | ||
253 | #define DSP2XGPRAM_START 0x105000 | ||
254 | #define DSP2XGPRAM_END 0x1051FC | ||
255 | #define DSP2YGPRAM_START 0x105800 | ||
256 | #define DSP2YGPRAM_END 0x1059FC | ||
257 | |||
258 | |||
259 | |||
260 | #define AUDIORINGIPDSP3_START 0x106000 | ||
261 | #define AUDIORINGIPDSP3_END 0x1063FC | ||
262 | #define AUDIORINGOPDSP3_START 0x106400 | ||
263 | #define AUDIORINGOPDSP3_END 0x1067FC | ||
264 | #define AUDPARARINGIODSP3_START 0x106800 | ||
265 | #define AUDPARARINGIODSP3_END 0x106BFC | ||
266 | #define DSP3LOCALHWREG_START 0x106C00 | ||
267 | #define DSP3LOCALHWREG_END 0x106C3C | ||
268 | #define DSP3XYRAMAGINDEX_START 0x106C40 | ||
269 | #define DSP3XYRAMAGINDEX_END 0x106C5C | ||
270 | #define DSP3XYRAMAGMDFR_START 0x106C60 | ||
271 | #define DSP3XYRAMAGMDFR_END 0x106C7C | ||
272 | #define DSP3INTCONTLVEC_START 0x106C80 | ||
273 | #define DSP3INTCONTLVEC_END 0x106CD8 | ||
274 | #define HOSTINTFPORTADDRCONTDSP3 0x106D40 | ||
275 | #define HOSTINTFPORTDATADSP3 0x106D44 | ||
276 | #define TIME0PERENBDSP3 0x106D60 | ||
277 | #define TIME0COUNTERDSP3 0x106D64 | ||
278 | #define TIME1PERENBDSP3 0x106D68 | ||
279 | #define TIME1COUNTERDSP3 0x106D6C | ||
280 | #define TIME2PERENBDSP3 0x106D70 | ||
281 | #define TIME2COUNTERDSP3 0x106D74 | ||
282 | #define TIME3PERENBDSP3 0x106D78 | ||
283 | #define TIME3COUNTERDSP3 0x106D7C | ||
284 | #define XRAMINDOPERREFNOUP_STARTDSP3 0x106D80 | ||
285 | #define XRAMINDOPERREFNOUP_ENDDSP3 0x106D9C | ||
286 | #define XRAMINDOPERREFUP_STARTDSP3 0x106DA0 | ||
287 | #define XRAMINDOPERREFUP_ENDDSP3 0x106DBC | ||
288 | #define YRAMINDOPERREFNOUP_STARTDSP3 0x106DC0 | ||
289 | #define YRAMINDOPERREFNOUP_ENDDSP3 0x106DDC | ||
290 | #define YRAMINDOPERREFUP_STARTDSP3 0x106DE0 | ||
291 | #define YRAMINDOPERREFUP_ENDDSP3 0x100DFC | ||
292 | |||
293 | #define DSP3CONDCODE 0x106E00 | ||
294 | #define DSP3STACKFLAG 0x106E04 | ||
295 | #define DSP3PROGCOUNTSTACKPTREG 0x106E08 | ||
296 | #define DSP3PROGCOUNTSTACKDATAREG 0x106E0C | ||
297 | #define DSP3CURLOOPADDRREG 0x106E10 | ||
298 | #define DSP3CURLOOPCOUNT 0x106E14 | ||
299 | #define DSP3TOPLOOPCOUNTSTACK 0x106E18 | ||
300 | #define DSP3TOPLOOPADDRSTACK 0x106E1C | ||
301 | #define DSP3LOOPSTACKPTR 0x106E20 | ||
302 | #define DSP3STASSTACKDATAREG 0x106E24 | ||
303 | #define DSP3STASSTACKPTR 0x106E28 | ||
304 | #define DSP3PROGCOUNT 0x106E2C | ||
305 | #define DSP3XYRAMBASE_START 0x106EA0 | ||
306 | #define DSP3XYRAMBASE_END 0x106EBC | ||
307 | #define DSP3XYRAMLENG_START 0x106EC0 | ||
308 | #define DSP3XYRAMLENG_END 0x106EDC | ||
309 | #define SEMAPHOREREGDSP3 0x106EE0 | ||
310 | #define DSP3INTCONTMASKREG 0x106EE4 | ||
311 | #define DSP3INTCONTPENDREG 0x106EE8 | ||
312 | #define DSP3INTCONTSERVINT 0x106EEC | ||
313 | #define GPIODSP3 0x106EFC | ||
314 | #define DMADSPBASEADDRREG_STARTDSP3 0x106F00 | ||
315 | #define DMADSPBASEADDRREG_ENDDSP3 0x106F1C | ||
316 | #define DMAHOSTBASEADDRREG_STARTDSP3 0x106F20 | ||
317 | #define DMAHOSTBASEADDRREG_ENDDSP3 0x106F3C | ||
318 | #define DMADSPCURADDRREG_STARTDSP3 0x106F40 | ||
319 | #define DMADSPCURADDRREG_ENDDSP3 0x106F5C | ||
320 | #define DMAHOSTCURADDRREG_STARTDSP3 0x106F60 | ||
321 | #define DMAHOSTCURADDRREG_ENDDSP3 0x106F7C | ||
322 | #define DMATANXCOUNTREG_STARTDSP3 0x106F80 | ||
323 | #define DMATANXCOUNTREG_ENDDSP3 0x106F9C | ||
324 | #define DMATIMEBUGREG_STARTDSP3 0x106FA0 | ||
325 | #define DMATIMEBUGREG_ENDDSP3 0x106FAC | ||
326 | #define DMACNTLMODFREG_STARTDSP3 0x106FA0 | ||
327 | #define DMACNTLMODFREG_ENDDSP3 0x106FAC | ||
328 | |||
329 | #define DMAGLOBSTATSREGDSP3 0x106FEC | ||
330 | #define DSP3XGPRAM_START 0x107000 | ||
331 | #define DSP3XGPRAM_END 0x1071FC | ||
332 | #define DSP3YGPRAM_START 0x107800 | ||
333 | #define DSP3YGPRAM_END 0x1079FC | ||
334 | |||
335 | /* end of DSP reg definitions */ | ||
336 | |||
337 | #define DSPAIMAP_START 0x108000 | ||
338 | #define DSPAIMAP_END 0x1083FC | ||
339 | #define DSPPIMAP_START 0x108400 | ||
340 | #define DSPPIMAP_END 0x1087FC | ||
341 | #define DSPPOMAP_START 0x108800 | ||
342 | #define DSPPOMAP_END 0x108BFC | ||
343 | #define DSPPOCTL 0x108C00 | ||
344 | #define TKCTL_START 0x110000 | ||
345 | #define TKCTL_END 0x110FFC | ||
346 | #define TKCC_START 0x111000 | ||
347 | #define TKCC_END 0x111FFC | ||
348 | #define TKIMAP_START 0x112000 | ||
349 | #define TKIMAP_END 0x112FFC | ||
350 | #define TKDCTR16 0x113000 | ||
351 | #define TKPB16 0x113004 | ||
352 | #define TKBS16 0x113008 | ||
353 | #define TKDCTR32 0x11300C | ||
354 | #define TKPB32 0x113010 | ||
355 | #define TKBS32 0x113014 | ||
356 | #define ICDCTR16 0x113018 | ||
357 | #define ITBS16 0x11301C | ||
358 | #define ICDCTR32 0x113020 | ||
359 | #define ITBS32 0x113024 | ||
360 | #define ITSTART 0x113028 | ||
361 | #define TKSQ 0x11302C | ||
362 | |||
363 | #define TKSCCTL_START 0x114000 | ||
364 | #define TKSCCTL_END 0x11403C | ||
365 | #define TKSCADR_START 0x114100 | ||
366 | #define TKSCADR_END 0x11413C | ||
367 | #define TKSCDATAX_START 0x114800 | ||
368 | #define TKSCDATAX_END 0x1149FC | ||
369 | #define TKPCDATAX_START 0x120000 | ||
370 | #define TKPCDATAX_END 0x12FFFC | ||
371 | |||
372 | #define MALSA 0x130000 | ||
373 | #define MAPPHA 0x130004 | ||
374 | #define MAPPLA 0x130008 | ||
375 | #define MALSB 0x130010 | ||
376 | #define MAPPHB 0x130014 | ||
377 | #define MAPPLB 0x130018 | ||
378 | |||
379 | #define TANSPORTMAPABREGS_START 0x130020 | ||
380 | #define TANSPORTMAPABREGS_END 0x13A2FC | ||
381 | |||
382 | #define PTPAHX 0x13B000 | ||
383 | #define PTPALX 0x13B004 | ||
384 | |||
385 | #define TANSPPAGETABLEPHYADDR015_START 0x13B008 | ||
386 | #define TANSPPAGETABLEPHYADDR015_END 0x13B07C | ||
387 | #define TRNQADRX_START 0x13B100 | ||
388 | #define TRNQADRX_END 0x13B13C | ||
389 | #define TRNQTIMX_START 0x13B200 | ||
390 | #define TRNQTIMX_END 0x13B23C | ||
391 | #define TRNQAPARMX_START 0x13B300 | ||
392 | #define TRNQAPARMX_END 0x13B33C | ||
393 | |||
394 | #define TRNQCNT 0x13B400 | ||
395 | #define TRNCTL 0x13B404 | ||
396 | #define TRNIS 0x13B408 | ||
397 | #define TRNCURTS 0x13B40C | ||
398 | |||
399 | #define AMOP_START 0x140000 | ||
400 | #define AMOPLO 0x140000 | ||
401 | #define AMOPHI 0x140004 | ||
402 | #define AMOP_END 0x147FFC | ||
403 | #define PMOP_START 0x148000 | ||
404 | #define PMOPLO 0x148000 | ||
405 | #define PMOPHI 0x148004 | ||
406 | #define PMOP_END 0x14FFFC | ||
407 | #define PCURR_START 0x150000 | ||
408 | #define PCURR_END 0x153FFC | ||
409 | #define PTRAG_START 0x154000 | ||
410 | #define PTRAG_END 0x157FFC | ||
411 | #define PSR_START 0x158000 | ||
412 | #define PSR_END 0x15BFFC | ||
413 | |||
414 | #define PFSTAT4SEG_START 0x160000 | ||
415 | #define PFSTAT4SEG_END 0x160BFC | ||
416 | #define PFSTAT2SEG_START 0x160C00 | ||
417 | #define PFSTAT2SEG_END 0x1617FC | ||
418 | #define PFTARG4SEG_START 0x164000 | ||
419 | #define PFTARG4SEG_END 0x164BFC | ||
420 | #define PFTARG2SEG_START 0x164C00 | ||
421 | #define PFTARG2SEG_END 0x1657FC | ||
422 | #define PFSR4SEG_START 0x168000 | ||
423 | #define PFSR4SEG_END 0x168BFC | ||
424 | #define PFSR2SEG_START 0x168C00 | ||
425 | #define PFSR2SEG_END 0x1697FC | ||
426 | #define PCURRMS4SEG_START 0x16C000 | ||
427 | #define PCURRMS4SEG_END 0x16CCFC | ||
428 | #define PCURRMS2SEG_START 0x16CC00 | ||
429 | #define PCURRMS2SEG_END 0x16D7FC | ||
430 | #define PTARGMS4SEG_START 0x170000 | ||
431 | #define PTARGMS4SEG_END 0x172FFC | ||
432 | #define PTARGMS2SEG_START 0x173000 | ||
433 | #define PTARGMS2SEG_END 0x1747FC | ||
434 | #define PSRMS4SEG_START 0x170000 | ||
435 | #define PSRMS4SEG_END 0x172FFC | ||
436 | #define PSRMS2SEG_START 0x173000 | ||
437 | #define PSRMS2SEG_END 0x1747FC | ||
438 | |||
439 | #define PRING_LO_START 0x190000 | ||
440 | #define PRING_LO_END 0x193FFC | ||
441 | #define PRING_HI_START 0x194000 | ||
442 | #define PRING_HI_END 0x197FFC | ||
443 | #define PRING_LO_HI_START 0x198000 | ||
444 | #define PRING_LO_HI 0x198000 | ||
445 | #define PRING_LO_HI_END 0x19BFFC | ||
446 | |||
447 | #define PINTFIFO 0x1A0000 | ||
448 | #define SRCCTL 0x1B0000 | ||
449 | #define SRCCCR 0x1B0004 | ||
450 | #define SRCIMAP 0x1B0008 | ||
451 | #define SRCODDC 0x1B000C | ||
452 | #define SRCCA 0x1B0010 | ||
453 | #define SRCCF 0x1B0014 | ||
454 | #define SRCSA 0x1B0018 | ||
455 | #define SRCLA 0x1B001C | ||
456 | #define SRCCTLSWR 0x1B0020 | ||
457 | |||
458 | /* SRC HERE */ | ||
459 | #define SRCALBA 0x1B002C | ||
460 | #define SRCMCTL 0x1B012C | ||
461 | #define SRCCERR 0x1B022C | ||
462 | #define SRCITB 0x1B032C | ||
463 | #define SRCIPM 0x1B082C | ||
464 | #define SRCIP 0x1B102C | ||
465 | #define SRCENBSTAT 0x1B202C | ||
466 | #define SRCENBLO 0x1B212C | ||
467 | #define SRCENBHI 0x1B222C | ||
468 | #define SRCENBS 0x1B232C | ||
469 | #define SRCENB 0x1B282C | ||
470 | #define SRCENB07 0x1B282C | ||
471 | #define SRCENBS07 0x1B302C | ||
472 | |||
473 | #define SRCDN0Z 0x1B0030 | ||
474 | #define SRCDN0Z0 0x1B0030 | ||
475 | #define SRCDN0Z1 0x1B0034 | ||
476 | #define SRCDN0Z2 0x1B0038 | ||
477 | #define SRCDN0Z3 0x1B003C | ||
478 | #define SRCDN1Z 0x1B0040 | ||
479 | #define SRCDN1Z0 0x1B0040 | ||
480 | #define SRCDN1Z1 0x1B0044 | ||
481 | #define SRCDN1Z2 0x1B0048 | ||
482 | #define SRCDN1Z3 0x1B004C | ||
483 | #define SRCDN1Z4 0x1B0050 | ||
484 | #define SRCDN1Z5 0x1B0054 | ||
485 | #define SRCDN1Z6 0x1B0058 | ||
486 | #define SRCDN1Z7 0x1B005C | ||
487 | #define SRCUPZ 0x1B0060 | ||
488 | #define SRCUPZ0 0x1B0060 | ||
489 | #define SRCUPZ1 0x1B0064 | ||
490 | #define SRCUPZ2 0x1B0068 | ||
491 | #define SRCUPZ3 0x1B006C | ||
492 | #define SRCUPZ4 0x1B0070 | ||
493 | #define SRCUPZ5 0x1B0074 | ||
494 | #define SRCUPZ6 0x1B0078 | ||
495 | #define SRCUPZ7 0x1B007C | ||
496 | #define SRCCD0 0x1B0080 | ||
497 | #define SRCCD1 0x1B0084 | ||
498 | #define SRCCD2 0x1B0088 | ||
499 | #define SRCCD3 0x1B008C | ||
500 | #define SRCCD4 0x1B0090 | ||
501 | #define SRCCD5 0x1B0094 | ||
502 | #define SRCCD6 0x1B0098 | ||
503 | #define SRCCD7 0x1B009C | ||
504 | #define SRCCD8 0x1B00A0 | ||
505 | #define SRCCD9 0x1B00A4 | ||
506 | #define SRCCDA 0x1B00A8 | ||
507 | #define SRCCDB 0x1B00AC | ||
508 | #define SRCCDC 0x1B00B0 | ||
509 | #define SRCCDD 0x1B00B4 | ||
510 | #define SRCCDE 0x1B00B8 | ||
511 | #define SRCCDF 0x1B00BC | ||
512 | #define SRCCD10 0x1B00C0 | ||
513 | #define SRCCD11 0x1B00C4 | ||
514 | #define SRCCD12 0x1B00C8 | ||
515 | #define SRCCD13 0x1B00CC | ||
516 | #define SRCCD14 0x1B00D0 | ||
517 | #define SRCCD15 0x1B00D4 | ||
518 | #define SRCCD16 0x1B00D8 | ||
519 | #define SRCCD17 0x1B00DC | ||
520 | #define SRCCD18 0x1B00E0 | ||
521 | #define SRCCD19 0x1B00E4 | ||
522 | #define SRCCD1A 0x1B00E8 | ||
523 | #define SRCCD1B 0x1B00EC | ||
524 | #define SRCCD1C 0x1B00F0 | ||
525 | #define SRCCD1D 0x1B00F4 | ||
526 | #define SRCCD1E 0x1B00F8 | ||
527 | #define SRCCD1F 0x1B00FC | ||
528 | |||
529 | #define SRCCONTRBLOCK_START 0x1B0100 | ||
530 | #define SRCCONTRBLOCK_END 0x1BFFFC | ||
531 | #define FILTOP_START 0x1C0000 | ||
532 | #define FILTOP_END 0x1C05FC | ||
533 | #define FILTIMAP_START 0x1C0800 | ||
534 | #define FILTIMAP_END 0x1C0DFC | ||
535 | #define FILTZ1_START 0x1C1000 | ||
536 | #define FILTZ1_END 0x1C15FC | ||
537 | #define FILTZ2_START 0x1C1800 | ||
538 | #define FILTZ2_END 0x1C1DFC | ||
539 | #define DAOIMAP_START 0x1C5000 | ||
540 | #define DAOIMAP 0x1C5000 | ||
541 | #define DAOIMAP_END 0x1C5124 | ||
542 | |||
543 | #define AC97D 0x1C5400 | ||
544 | #define AC97A 0x1C5404 | ||
545 | #define AC97CTL 0x1C5408 | ||
546 | #define I2SCTL 0x1C5420 | ||
547 | |||
548 | #define SPOS 0x1C5440 | ||
549 | #define SPOSA 0x1C5440 | ||
550 | #define SPOSB 0x1C5444 | ||
551 | #define SPOSC 0x1C5448 | ||
552 | #define SPOSD 0x1C544C | ||
553 | |||
554 | #define SPISA 0x1C5450 | ||
555 | #define SPISB 0x1C5454 | ||
556 | #define SPISC 0x1C5458 | ||
557 | #define SPISD 0x1C545C | ||
558 | |||
559 | #define SPFSCTL 0x1C5460 | ||
560 | |||
561 | #define SPFS0 0x1C5468 | ||
562 | #define SPFS1 0x1C546C | ||
563 | #define SPFS2 0x1C5470 | ||
564 | #define SPFS3 0x1C5474 | ||
565 | #define SPFS4 0x1C5478 | ||
566 | #define SPFS5 0x1C547C | ||
567 | |||
568 | #define SPOCTL 0x1C5480 | ||
569 | #define SPICTL 0x1C5484 | ||
570 | #define SPISTS 0x1C5488 | ||
571 | #define SPINTP 0x1C548C | ||
572 | #define SPINTE 0x1C5490 | ||
573 | #define SPUTCTLAB 0x1C5494 | ||
574 | #define SPUTCTLCD 0x1C5498 | ||
575 | |||
576 | #define SRTSPA 0x1C54C0 | ||
577 | #define SRTSPB 0x1C54C4 | ||
578 | #define SRTSPC 0x1C54C8 | ||
579 | #define SRTSPD 0x1C54CC | ||
580 | |||
581 | #define SRTSCTL 0x1C54D0 | ||
582 | #define SRTSCTLA 0x1C54D0 | ||
583 | #define SRTSCTLB 0x1C54D4 | ||
584 | #define SRTSCTLC 0x1C54D8 | ||
585 | #define SRTSCTLD 0x1C54DC | ||
586 | |||
587 | #define SRTI2S 0x1C54E0 | ||
588 | #define SRTICTL 0x1C54F0 | ||
589 | |||
590 | #define WC 0x1C6000 | ||
591 | #define TIMR 0x1C6004 | ||
592 | # define TIMR_IE (1<<15) | ||
593 | # define TIMR_IP (1<<14) | ||
594 | |||
595 | #define GIP 0x1C6010 | ||
596 | #define GIE 0x1C6014 | ||
597 | #define DIE 0x1C6018 | ||
598 | #define DIC 0x1C601C | ||
599 | #define GPIO 0x1C6020 | ||
600 | #define GPIOCTL 0x1C6024 | ||
601 | #define GPIP 0x1C6028 | ||
602 | #define GPIE 0x1C602C | ||
603 | #define DSPINT0 0x1C6030 | ||
604 | #define DSPEIOC 0x1C6034 | ||
605 | #define MUADAT 0x1C6040 | ||
606 | #define MUACMD 0x1C6044 | ||
607 | #define MUASTAT 0x1C6044 | ||
608 | #define MUBDAT 0x1C6048 | ||
609 | #define MUBCMD 0x1C604C | ||
610 | #define MUBSTAT 0x1C604C | ||
611 | #define UARTCMA 0x1C6050 | ||
612 | #define UARTCMB 0x1C6054 | ||
613 | #define UARTIP 0x1C6058 | ||
614 | #define UARTIE 0x1C605C | ||
615 | #define PLLCTL 0x1C6060 | ||
616 | #define PLLDCD 0x1C6064 | ||
617 | #define GCTL 0x1C6070 | ||
618 | #define ID0 0x1C6080 | ||
619 | #define ID1 0x1C6084 | ||
620 | #define ID2 0x1C6088 | ||
621 | #define ID3 0x1C608C | ||
622 | #define SDRCTL 0x1C7000 | ||
623 | |||
624 | |||
625 | #define I2SA_L 0x0L | ||
626 | #define I2SA_R 0x1L | ||
627 | #define I2SB_L 0x8L | ||
628 | #define I2SB_R 0x9L | ||
629 | #define I2SC_L 0x10L | ||
630 | #define I2SC_R 0x11L | ||
631 | #define I2SD_L 0x18L | ||
632 | #define I2SD_R 0x19L | ||
633 | |||
634 | #endif /* CT20K1REG_H */ | ||
635 | |||
636 | |||
diff --git a/sound/pci/ctxfi/ct20k2reg.h b/sound/pci/ctxfi/ct20k2reg.h new file mode 100644 index 000000000000..2d07986f57cc --- /dev/null +++ b/sound/pci/ctxfi/ct20k2reg.h | |||
@@ -0,0 +1,85 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | */ | ||
8 | |||
9 | #ifndef _20K2REGISTERS_H_ | ||
10 | #define _20K2REGISTERS_H_ | ||
11 | |||
12 | |||
13 | /* Timer Registers */ | ||
14 | #define TIMER_TIMR 0x1B7004 | ||
15 | #define INTERRUPT_GIP 0x1B7010 | ||
16 | #define INTERRUPT_GIE 0x1B7014 | ||
17 | |||
18 | /* I2C Registers */ | ||
19 | #define I2C_IF_ADDRESS 0x1B9000 | ||
20 | #define I2C_IF_WDATA 0x1B9004 | ||
21 | #define I2C_IF_RDATA 0x1B9008 | ||
22 | #define I2C_IF_STATUS 0x1B900C | ||
23 | #define I2C_IF_WLOCK 0x1B9010 | ||
24 | |||
25 | /* Global Control Registers */ | ||
26 | #define GLOBAL_CNTL_GCTL 0x1B7090 | ||
27 | |||
28 | /* PLL Registers */ | ||
29 | #define PLL_CTL 0x1B7080 | ||
30 | #define PLL_STAT 0x1B7084 | ||
31 | #define PLL_ENB 0x1B7088 | ||
32 | |||
33 | /* SRC Registers */ | ||
34 | #define SRC_CTL 0x1A0000 /* 0x1A0000 + (256 * Chn) */ | ||
35 | #define SRC_CCR 0x1A0004 /* 0x1A0004 + (256 * Chn) */ | ||
36 | #define SRC_IMAP 0x1A0008 /* 0x1A0008 + (256 * Chn) */ | ||
37 | #define SRC_CA 0x1A0010 /* 0x1A0010 + (256 * Chn) */ | ||
38 | #define SRC_CF 0x1A0014 /* 0x1A0014 + (256 * Chn) */ | ||
39 | #define SRC_SA 0x1A0018 /* 0x1A0018 + (256 * Chn) */ | ||
40 | #define SRC_LA 0x1A001C /* 0x1A001C + (256 * Chn) */ | ||
41 | #define SRC_CTLSWR 0x1A0020 /* 0x1A0020 + (256 * Chn) */ | ||
42 | #define SRC_CD 0x1A0080 /* 0x1A0080 + (256 * Chn) + (4 * Regn) */ | ||
43 | #define SRC_MCTL 0x1A012C | ||
44 | #define SRC_IP 0x1A102C /* 0x1A102C + (256 * Regn) */ | ||
45 | #define SRC_ENB 0x1A282C /* 0x1A282C + (256 * Regn) */ | ||
46 | #define SRC_ENBSTAT 0x1A202C | ||
47 | #define SRC_ENBSA 0x1A232C | ||
48 | #define SRC_DN0Z 0x1A0030 | ||
49 | #define SRC_DN1Z 0x1A0040 | ||
50 | #define SRC_UPZ 0x1A0060 | ||
51 | |||
52 | /* GPIO Registers */ | ||
53 | #define GPIO_DATA 0x1B7020 | ||
54 | #define GPIO_CTRL 0x1B7024 | ||
55 | |||
56 | /* Virtual memory registers */ | ||
57 | #define VMEM_PTPAL 0x1C6300 /* 0x1C6300 + (16 * Chn) */ | ||
58 | #define VMEM_PTPAH 0x1C6304 /* 0x1C6304 + (16 * Chn) */ | ||
59 | #define VMEM_CTL 0x1C7000 | ||
60 | |||
61 | /* Transport Registers */ | ||
62 | #define TRANSPORT_ENB 0x1B6000 | ||
63 | #define TRANSPORT_CTL 0x1B6004 | ||
64 | #define TRANSPORT_INT 0x1B6008 | ||
65 | |||
66 | /* Audio IO */ | ||
67 | #define AUDIO_IO_AIM 0x1B5000 /* 0x1B5000 + (0x04 * Chn) */ | ||
68 | #define AUDIO_IO_TX_CTL 0x1B5400 /* 0x1B5400 + (0x40 * Chn) */ | ||
69 | #define AUDIO_IO_TX_CSTAT_L 0x1B5408 /* 0x1B5408 + (0x40 * Chn) */ | ||
70 | #define AUDIO_IO_TX_CSTAT_H 0x1B540C /* 0x1B540C + (0x40 * Chn) */ | ||
71 | #define AUDIO_IO_RX_CTL 0x1B5410 /* 0x1B5410 + (0x40 * Chn) */ | ||
72 | #define AUDIO_IO_RX_SRT_CTL 0x1B5420 /* 0x1B5420 + (0x40 * Chn) */ | ||
73 | #define AUDIO_IO_MCLK 0x1B5600 | ||
74 | #define AUDIO_IO_TX_BLRCLK 0x1B5604 | ||
75 | #define AUDIO_IO_RX_BLRCLK 0x1B5608 | ||
76 | |||
77 | /* Mixer */ | ||
78 | #define MIXER_AMOPLO 0x130000 /* 0x130000 + (8 * Chn) [4095 : 0] */ | ||
79 | #define MIXER_AMOPHI 0x130004 /* 0x130004 + (8 * Chn) [4095 : 0] */ | ||
80 | #define MIXER_PRING_LO_HI 0x188000 /* 0x188000 + (4 * Chn) [4095 : 0] */ | ||
81 | #define MIXER_PMOPLO 0x138000 /* 0x138000 + (8 * Chn) [4095 : 0] */ | ||
82 | #define MIXER_PMOPHI 0x138004 /* 0x138004 + (8 * Chn) [4095 : 0] */ | ||
83 | #define MIXER_AR_ENABLE 0x19000C | ||
84 | |||
85 | #endif | ||
diff --git a/sound/pci/ctxfi/ctamixer.c b/sound/pci/ctxfi/ctamixer.c new file mode 100644 index 000000000000..a1db51b3ead8 --- /dev/null +++ b/sound/pci/ctxfi/ctamixer.c | |||
@@ -0,0 +1,488 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctamixer.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of the Audio Mixer | ||
12 | * resource management object. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 21 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "ctamixer.h" | ||
20 | #include "cthardware.h" | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #define AMIXER_RESOURCE_NUM 256 | ||
24 | #define SUM_RESOURCE_NUM 256 | ||
25 | |||
26 | #define AMIXER_Y_IMMEDIATE 1 | ||
27 | |||
28 | #define BLANK_SLOT 4094 | ||
29 | |||
30 | static int amixer_master(struct rsc *rsc) | ||
31 | { | ||
32 | rsc->conj = 0; | ||
33 | return rsc->idx = container_of(rsc, struct amixer, rsc)->idx[0]; | ||
34 | } | ||
35 | |||
36 | static int amixer_next_conj(struct rsc *rsc) | ||
37 | { | ||
38 | rsc->conj++; | ||
39 | return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; | ||
40 | } | ||
41 | |||
42 | static int amixer_index(const struct rsc *rsc) | ||
43 | { | ||
44 | return container_of(rsc, struct amixer, rsc)->idx[rsc->conj]; | ||
45 | } | ||
46 | |||
47 | static int amixer_output_slot(const struct rsc *rsc) | ||
48 | { | ||
49 | return (amixer_index(rsc) << 4) + 0x4; | ||
50 | } | ||
51 | |||
52 | static struct rsc_ops amixer_basic_rsc_ops = { | ||
53 | .master = amixer_master, | ||
54 | .next_conj = amixer_next_conj, | ||
55 | .index = amixer_index, | ||
56 | .output_slot = amixer_output_slot, | ||
57 | }; | ||
58 | |||
59 | static int amixer_set_input(struct amixer *amixer, struct rsc *rsc) | ||
60 | { | ||
61 | struct hw *hw; | ||
62 | |||
63 | hw = amixer->rsc.hw; | ||
64 | hw->amixer_set_mode(amixer->rsc.ctrl_blk, AMIXER_Y_IMMEDIATE); | ||
65 | amixer->input = rsc; | ||
66 | if (NULL == rsc) | ||
67 | hw->amixer_set_x(amixer->rsc.ctrl_blk, BLANK_SLOT); | ||
68 | else | ||
69 | hw->amixer_set_x(amixer->rsc.ctrl_blk, | ||
70 | rsc->ops->output_slot(rsc)); | ||
71 | |||
72 | return 0; | ||
73 | } | ||
74 | |||
75 | /* y is a 14-bit immediate constant */ | ||
76 | static int amixer_set_y(struct amixer *amixer, unsigned int y) | ||
77 | { | ||
78 | struct hw *hw; | ||
79 | |||
80 | hw = amixer->rsc.hw; | ||
81 | hw->amixer_set_y(amixer->rsc.ctrl_blk, y); | ||
82 | |||
83 | return 0; | ||
84 | } | ||
85 | |||
86 | static int amixer_set_invalid_squash(struct amixer *amixer, unsigned int iv) | ||
87 | { | ||
88 | struct hw *hw; | ||
89 | |||
90 | hw = amixer->rsc.hw; | ||
91 | hw->amixer_set_iv(amixer->rsc.ctrl_blk, iv); | ||
92 | |||
93 | return 0; | ||
94 | } | ||
95 | |||
96 | static int amixer_set_sum(struct amixer *amixer, struct sum *sum) | ||
97 | { | ||
98 | struct hw *hw; | ||
99 | |||
100 | hw = amixer->rsc.hw; | ||
101 | amixer->sum = sum; | ||
102 | if (NULL == sum) { | ||
103 | hw->amixer_set_se(amixer->rsc.ctrl_blk, 0); | ||
104 | } else { | ||
105 | hw->amixer_set_se(amixer->rsc.ctrl_blk, 1); | ||
106 | hw->amixer_set_sadr(amixer->rsc.ctrl_blk, | ||
107 | sum->rsc.ops->index(&sum->rsc)); | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | static int amixer_commit_write(struct amixer *amixer) | ||
114 | { | ||
115 | struct hw *hw; | ||
116 | unsigned int index; | ||
117 | int i; | ||
118 | struct rsc *input; | ||
119 | struct sum *sum; | ||
120 | |||
121 | hw = amixer->rsc.hw; | ||
122 | input = amixer->input; | ||
123 | sum = amixer->sum; | ||
124 | |||
125 | /* Program master and conjugate resources */ | ||
126 | amixer->rsc.ops->master(&amixer->rsc); | ||
127 | if (NULL != input) | ||
128 | input->ops->master(input); | ||
129 | |||
130 | if (NULL != sum) | ||
131 | sum->rsc.ops->master(&sum->rsc); | ||
132 | |||
133 | for (i = 0; i < amixer->rsc.msr; i++) { | ||
134 | hw->amixer_set_dirty_all(amixer->rsc.ctrl_blk); | ||
135 | if (NULL != input) { | ||
136 | hw->amixer_set_x(amixer->rsc.ctrl_blk, | ||
137 | input->ops->output_slot(input)); | ||
138 | input->ops->next_conj(input); | ||
139 | } | ||
140 | if (NULL != sum) { | ||
141 | hw->amixer_set_sadr(amixer->rsc.ctrl_blk, | ||
142 | sum->rsc.ops->index(&sum->rsc)); | ||
143 | sum->rsc.ops->next_conj(&sum->rsc); | ||
144 | } | ||
145 | index = amixer->rsc.ops->output_slot(&amixer->rsc); | ||
146 | hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); | ||
147 | amixer->rsc.ops->next_conj(&amixer->rsc); | ||
148 | } | ||
149 | amixer->rsc.ops->master(&amixer->rsc); | ||
150 | if (NULL != input) | ||
151 | input->ops->master(input); | ||
152 | |||
153 | if (NULL != sum) | ||
154 | sum->rsc.ops->master(&sum->rsc); | ||
155 | |||
156 | return 0; | ||
157 | } | ||
158 | |||
159 | static int amixer_commit_raw_write(struct amixer *amixer) | ||
160 | { | ||
161 | struct hw *hw; | ||
162 | unsigned int index; | ||
163 | |||
164 | hw = amixer->rsc.hw; | ||
165 | index = amixer->rsc.ops->output_slot(&amixer->rsc); | ||
166 | hw->amixer_commit_write(hw, index, amixer->rsc.ctrl_blk); | ||
167 | |||
168 | return 0; | ||
169 | } | ||
170 | |||
171 | static int amixer_get_y(struct amixer *amixer) | ||
172 | { | ||
173 | struct hw *hw; | ||
174 | |||
175 | hw = amixer->rsc.hw; | ||
176 | return hw->amixer_get_y(amixer->rsc.ctrl_blk); | ||
177 | } | ||
178 | |||
179 | static int amixer_setup(struct amixer *amixer, struct rsc *input, | ||
180 | unsigned int scale, struct sum *sum) | ||
181 | { | ||
182 | amixer_set_input(amixer, input); | ||
183 | amixer_set_y(amixer, scale); | ||
184 | amixer_set_sum(amixer, sum); | ||
185 | amixer_commit_write(amixer); | ||
186 | return 0; | ||
187 | } | ||
188 | |||
189 | static struct amixer_rsc_ops amixer_ops = { | ||
190 | .set_input = amixer_set_input, | ||
191 | .set_invalid_squash = amixer_set_invalid_squash, | ||
192 | .set_scale = amixer_set_y, | ||
193 | .set_sum = amixer_set_sum, | ||
194 | .commit_write = amixer_commit_write, | ||
195 | .commit_raw_write = amixer_commit_raw_write, | ||
196 | .setup = amixer_setup, | ||
197 | .get_scale = amixer_get_y, | ||
198 | }; | ||
199 | |||
200 | static int amixer_rsc_init(struct amixer *amixer, | ||
201 | const struct amixer_desc *desc, | ||
202 | struct amixer_mgr *mgr) | ||
203 | { | ||
204 | int err; | ||
205 | |||
206 | err = rsc_init(&amixer->rsc, amixer->idx[0], | ||
207 | AMIXER, desc->msr, mgr->mgr.hw); | ||
208 | if (err) | ||
209 | return err; | ||
210 | |||
211 | /* Set amixer specific operations */ | ||
212 | amixer->rsc.ops = &amixer_basic_rsc_ops; | ||
213 | amixer->ops = &amixer_ops; | ||
214 | amixer->input = NULL; | ||
215 | amixer->sum = NULL; | ||
216 | |||
217 | amixer_setup(amixer, NULL, 0, NULL); | ||
218 | |||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int amixer_rsc_uninit(struct amixer *amixer) | ||
223 | { | ||
224 | amixer_setup(amixer, NULL, 0, NULL); | ||
225 | rsc_uninit(&amixer->rsc); | ||
226 | amixer->ops = NULL; | ||
227 | amixer->input = NULL; | ||
228 | amixer->sum = NULL; | ||
229 | return 0; | ||
230 | } | ||
231 | |||
232 | static int get_amixer_rsc(struct amixer_mgr *mgr, | ||
233 | const struct amixer_desc *desc, | ||
234 | struct amixer **ramixer) | ||
235 | { | ||
236 | int err, i; | ||
237 | unsigned int idx; | ||
238 | struct amixer *amixer; | ||
239 | unsigned long flags; | ||
240 | |||
241 | *ramixer = NULL; | ||
242 | |||
243 | /* Allocate mem for amixer resource */ | ||
244 | amixer = kzalloc(sizeof(*amixer), GFP_KERNEL); | ||
245 | if (NULL == amixer) { | ||
246 | err = -ENOMEM; | ||
247 | return err; | ||
248 | } | ||
249 | |||
250 | /* Check whether there are sufficient | ||
251 | * amixer resources to meet request. */ | ||
252 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
253 | for (i = 0; i < desc->msr; i++) { | ||
254 | err = mgr_get_resource(&mgr->mgr, 1, &idx); | ||
255 | if (err) | ||
256 | break; | ||
257 | |||
258 | amixer->idx[i] = idx; | ||
259 | } | ||
260 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
261 | if (err) { | ||
262 | printk(KERN_ERR "ctxfi: Can't meet AMIXER resource request!\n"); | ||
263 | goto error; | ||
264 | } | ||
265 | |||
266 | err = amixer_rsc_init(amixer, desc, mgr); | ||
267 | if (err) | ||
268 | goto error; | ||
269 | |||
270 | *ramixer = amixer; | ||
271 | |||
272 | return 0; | ||
273 | |||
274 | error: | ||
275 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
276 | for (i--; i >= 0; i--) | ||
277 | mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); | ||
278 | |||
279 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
280 | kfree(amixer); | ||
281 | return err; | ||
282 | } | ||
283 | |||
284 | static int put_amixer_rsc(struct amixer_mgr *mgr, struct amixer *amixer) | ||
285 | { | ||
286 | unsigned long flags; | ||
287 | int i; | ||
288 | |||
289 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
290 | for (i = 0; i < amixer->rsc.msr; i++) | ||
291 | mgr_put_resource(&mgr->mgr, 1, amixer->idx[i]); | ||
292 | |||
293 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
294 | amixer_rsc_uninit(amixer); | ||
295 | kfree(amixer); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr) | ||
301 | { | ||
302 | int err; | ||
303 | struct amixer_mgr *amixer_mgr; | ||
304 | |||
305 | *ramixer_mgr = NULL; | ||
306 | amixer_mgr = kzalloc(sizeof(*amixer_mgr), GFP_KERNEL); | ||
307 | if (NULL == amixer_mgr) | ||
308 | return -ENOMEM; | ||
309 | |||
310 | err = rsc_mgr_init(&amixer_mgr->mgr, AMIXER, AMIXER_RESOURCE_NUM, hw); | ||
311 | if (err) | ||
312 | goto error; | ||
313 | |||
314 | spin_lock_init(&amixer_mgr->mgr_lock); | ||
315 | |||
316 | amixer_mgr->get_amixer = get_amixer_rsc; | ||
317 | amixer_mgr->put_amixer = put_amixer_rsc; | ||
318 | |||
319 | *ramixer_mgr = amixer_mgr; | ||
320 | |||
321 | return 0; | ||
322 | |||
323 | error: | ||
324 | kfree(amixer_mgr); | ||
325 | return err; | ||
326 | } | ||
327 | |||
328 | int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr) | ||
329 | { | ||
330 | rsc_mgr_uninit(&amixer_mgr->mgr); | ||
331 | kfree(amixer_mgr); | ||
332 | return 0; | ||
333 | } | ||
334 | |||
335 | /* SUM resource management */ | ||
336 | |||
337 | static int sum_master(struct rsc *rsc) | ||
338 | { | ||
339 | rsc->conj = 0; | ||
340 | return rsc->idx = container_of(rsc, struct sum, rsc)->idx[0]; | ||
341 | } | ||
342 | |||
343 | static int sum_next_conj(struct rsc *rsc) | ||
344 | { | ||
345 | rsc->conj++; | ||
346 | return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; | ||
347 | } | ||
348 | |||
349 | static int sum_index(const struct rsc *rsc) | ||
350 | { | ||
351 | return container_of(rsc, struct sum, rsc)->idx[rsc->conj]; | ||
352 | } | ||
353 | |||
354 | static int sum_output_slot(const struct rsc *rsc) | ||
355 | { | ||
356 | return (sum_index(rsc) << 4) + 0xc; | ||
357 | } | ||
358 | |||
359 | static struct rsc_ops sum_basic_rsc_ops = { | ||
360 | .master = sum_master, | ||
361 | .next_conj = sum_next_conj, | ||
362 | .index = sum_index, | ||
363 | .output_slot = sum_output_slot, | ||
364 | }; | ||
365 | |||
366 | static int sum_rsc_init(struct sum *sum, | ||
367 | const struct sum_desc *desc, | ||
368 | struct sum_mgr *mgr) | ||
369 | { | ||
370 | int err; | ||
371 | |||
372 | err = rsc_init(&sum->rsc, sum->idx[0], SUM, desc->msr, mgr->mgr.hw); | ||
373 | if (err) | ||
374 | return err; | ||
375 | |||
376 | sum->rsc.ops = &sum_basic_rsc_ops; | ||
377 | |||
378 | return 0; | ||
379 | } | ||
380 | |||
381 | static int sum_rsc_uninit(struct sum *sum) | ||
382 | { | ||
383 | rsc_uninit(&sum->rsc); | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static int get_sum_rsc(struct sum_mgr *mgr, | ||
388 | const struct sum_desc *desc, | ||
389 | struct sum **rsum) | ||
390 | { | ||
391 | int err, i; | ||
392 | unsigned int idx; | ||
393 | struct sum *sum; | ||
394 | unsigned long flags; | ||
395 | |||
396 | *rsum = NULL; | ||
397 | |||
398 | /* Allocate mem for sum resource */ | ||
399 | sum = kzalloc(sizeof(*sum), GFP_KERNEL); | ||
400 | if (NULL == sum) { | ||
401 | err = -ENOMEM; | ||
402 | return err; | ||
403 | } | ||
404 | |||
405 | /* Check whether there are sufficient sum resources to meet request. */ | ||
406 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
407 | for (i = 0; i < desc->msr; i++) { | ||
408 | err = mgr_get_resource(&mgr->mgr, 1, &idx); | ||
409 | if (err) | ||
410 | break; | ||
411 | |||
412 | sum->idx[i] = idx; | ||
413 | } | ||
414 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
415 | if (err) { | ||
416 | printk(KERN_ERR "ctxfi: Can't meet SUM resource request!\n"); | ||
417 | goto error; | ||
418 | } | ||
419 | |||
420 | err = sum_rsc_init(sum, desc, mgr); | ||
421 | if (err) | ||
422 | goto error; | ||
423 | |||
424 | *rsum = sum; | ||
425 | |||
426 | return 0; | ||
427 | |||
428 | error: | ||
429 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
430 | for (i--; i >= 0; i--) | ||
431 | mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); | ||
432 | |||
433 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
434 | kfree(sum); | ||
435 | return err; | ||
436 | } | ||
437 | |||
438 | static int put_sum_rsc(struct sum_mgr *mgr, struct sum *sum) | ||
439 | { | ||
440 | unsigned long flags; | ||
441 | int i; | ||
442 | |||
443 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
444 | for (i = 0; i < sum->rsc.msr; i++) | ||
445 | mgr_put_resource(&mgr->mgr, 1, sum->idx[i]); | ||
446 | |||
447 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
448 | sum_rsc_uninit(sum); | ||
449 | kfree(sum); | ||
450 | |||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr) | ||
455 | { | ||
456 | int err; | ||
457 | struct sum_mgr *sum_mgr; | ||
458 | |||
459 | *rsum_mgr = NULL; | ||
460 | sum_mgr = kzalloc(sizeof(*sum_mgr), GFP_KERNEL); | ||
461 | if (NULL == sum_mgr) | ||
462 | return -ENOMEM; | ||
463 | |||
464 | err = rsc_mgr_init(&sum_mgr->mgr, SUM, SUM_RESOURCE_NUM, hw); | ||
465 | if (err) | ||
466 | goto error; | ||
467 | |||
468 | spin_lock_init(&sum_mgr->mgr_lock); | ||
469 | |||
470 | sum_mgr->get_sum = get_sum_rsc; | ||
471 | sum_mgr->put_sum = put_sum_rsc; | ||
472 | |||
473 | *rsum_mgr = sum_mgr; | ||
474 | |||
475 | return 0; | ||
476 | |||
477 | error: | ||
478 | kfree(sum_mgr); | ||
479 | return err; | ||
480 | } | ||
481 | |||
482 | int sum_mgr_destroy(struct sum_mgr *sum_mgr) | ||
483 | { | ||
484 | rsc_mgr_uninit(&sum_mgr->mgr); | ||
485 | kfree(sum_mgr); | ||
486 | return 0; | ||
487 | } | ||
488 | |||
diff --git a/sound/pci/ctxfi/ctamixer.h b/sound/pci/ctxfi/ctamixer.h new file mode 100644 index 000000000000..cc49e5ab4750 --- /dev/null +++ b/sound/pci/ctxfi/ctamixer.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctamixer.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of the Audio Mixer | ||
12 | * resource management object. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 21 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef CTAMIXER_H | ||
20 | #define CTAMIXER_H | ||
21 | |||
22 | #include "ctresource.h" | ||
23 | #include <linux/spinlock.h> | ||
24 | |||
25 | /* Define the descriptor of a summation node resource */ | ||
26 | struct sum { | ||
27 | struct rsc rsc; /* Basic resource info */ | ||
28 | unsigned char idx[8]; | ||
29 | }; | ||
30 | |||
31 | /* Define sum resource request description info */ | ||
32 | struct sum_desc { | ||
33 | unsigned int msr; | ||
34 | }; | ||
35 | |||
36 | struct sum_mgr { | ||
37 | struct rsc_mgr mgr; /* Basic resource manager info */ | ||
38 | spinlock_t mgr_lock; | ||
39 | |||
40 | /* request one sum resource */ | ||
41 | int (*get_sum)(struct sum_mgr *mgr, | ||
42 | const struct sum_desc *desc, struct sum **rsum); | ||
43 | /* return one sum resource */ | ||
44 | int (*put_sum)(struct sum_mgr *mgr, struct sum *sum); | ||
45 | }; | ||
46 | |||
47 | /* Constructor and destructor of daio resource manager */ | ||
48 | int sum_mgr_create(void *hw, struct sum_mgr **rsum_mgr); | ||
49 | int sum_mgr_destroy(struct sum_mgr *sum_mgr); | ||
50 | |||
51 | /* Define the descriptor of a amixer resource */ | ||
52 | struct amixer_rsc_ops; | ||
53 | |||
54 | struct amixer { | ||
55 | struct rsc rsc; /* Basic resource info */ | ||
56 | unsigned char idx[8]; | ||
57 | struct rsc *input; /* pointer to a resource acting as source */ | ||
58 | struct sum *sum; /* Put amixer output to this summation node */ | ||
59 | struct amixer_rsc_ops *ops; /* AMixer specific operations */ | ||
60 | }; | ||
61 | |||
62 | struct amixer_rsc_ops { | ||
63 | int (*set_input)(struct amixer *amixer, struct rsc *rsc); | ||
64 | int (*set_scale)(struct amixer *amixer, unsigned int scale); | ||
65 | int (*set_invalid_squash)(struct amixer *amixer, unsigned int iv); | ||
66 | int (*set_sum)(struct amixer *amixer, struct sum *sum); | ||
67 | int (*commit_write)(struct amixer *amixer); | ||
68 | /* Only for interleaved recording */ | ||
69 | int (*commit_raw_write)(struct amixer *amixer); | ||
70 | int (*setup)(struct amixer *amixer, struct rsc *input, | ||
71 | unsigned int scale, struct sum *sum); | ||
72 | int (*get_scale)(struct amixer *amixer); | ||
73 | }; | ||
74 | |||
75 | /* Define amixer resource request description info */ | ||
76 | struct amixer_desc { | ||
77 | unsigned int msr; | ||
78 | }; | ||
79 | |||
80 | struct amixer_mgr { | ||
81 | struct rsc_mgr mgr; /* Basic resource manager info */ | ||
82 | spinlock_t mgr_lock; | ||
83 | |||
84 | /* request one amixer resource */ | ||
85 | int (*get_amixer)(struct amixer_mgr *mgr, | ||
86 | const struct amixer_desc *desc, | ||
87 | struct amixer **ramixer); | ||
88 | /* return one amixer resource */ | ||
89 | int (*put_amixer)(struct amixer_mgr *mgr, struct amixer *amixer); | ||
90 | }; | ||
91 | |||
92 | /* Constructor and destructor of amixer resource manager */ | ||
93 | int amixer_mgr_create(void *hw, struct amixer_mgr **ramixer_mgr); | ||
94 | int amixer_mgr_destroy(struct amixer_mgr *amixer_mgr); | ||
95 | |||
96 | #endif /* CTAMIXER_H */ | ||
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c new file mode 100644 index 000000000000..80fb2baed7a7 --- /dev/null +++ b/sound/pci/ctxfi/ctatc.c | |||
@@ -0,0 +1,1619 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctatc.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of the device resource management | ||
12 | * object. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date Mar 28 2008 | ||
16 | */ | ||
17 | |||
18 | #include "ctatc.h" | ||
19 | #include "ctpcm.h" | ||
20 | #include "ctmixer.h" | ||
21 | #include "cthardware.h" | ||
22 | #include "ctsrc.h" | ||
23 | #include "ctamixer.h" | ||
24 | #include "ctdaio.h" | ||
25 | #include "cttimer.h" | ||
26 | #include <linux/delay.h> | ||
27 | #include <sound/pcm.h> | ||
28 | #include <sound/control.h> | ||
29 | #include <sound/asoundef.h> | ||
30 | |||
31 | #define MONO_SUM_SCALE 0x19a8 /* 2^(-0.5) in 14-bit floating format */ | ||
32 | #define DAIONUM 7 | ||
33 | #define MAX_MULTI_CHN 8 | ||
34 | |||
35 | #define IEC958_DEFAULT_CON ((IEC958_AES0_NONAUDIO \ | ||
36 | | IEC958_AES0_CON_NOT_COPYRIGHT) \ | ||
37 | | ((IEC958_AES1_CON_MIXER \ | ||
38 | | IEC958_AES1_CON_ORIGINAL) << 8) \ | ||
39 | | (0x10 << 16) \ | ||
40 | | ((IEC958_AES3_CON_FS_48000) << 24)) | ||
41 | |||
42 | static struct snd_pci_quirk __devinitdata subsys_20k1_list[] = { | ||
43 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0022, "SB055x", CTSB055X), | ||
44 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x002f, "SB055x", CTSB055X), | ||
45 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0029, "SB073x", CTSB073X), | ||
46 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, 0x0031, "SB073x", CTSB073X), | ||
47 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, 0x6000, | ||
48 | "UAA", CTUAA), | ||
49 | SND_PCI_QUIRK_VENDOR(PCI_VENDOR_ID_CREATIVE, | ||
50 | "Unknown", CT20K1_UNKNOWN), | ||
51 | { } /* terminator */ | ||
52 | }; | ||
53 | |||
54 | static struct snd_pci_quirk __devinitdata subsys_20k2_list[] = { | ||
55 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB0760, | ||
56 | "SB0760", CTSB0760), | ||
57 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08801, | ||
58 | "SB0880", CTSB0880), | ||
59 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08802, | ||
60 | "SB0880", CTSB0880), | ||
61 | SND_PCI_QUIRK(PCI_VENDOR_ID_CREATIVE, PCI_SUBDEVICE_ID_CREATIVE_SB08803, | ||
62 | "SB0880", CTSB0880), | ||
63 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_CREATIVE, 0xf000, | ||
64 | PCI_SUBDEVICE_ID_CREATIVE_HENDRIX, "HENDRIX", | ||
65 | CTHENDRIX), | ||
66 | { } /* terminator */ | ||
67 | }; | ||
68 | |||
69 | static const char *ct_subsys_name[NUM_CTCARDS] = { | ||
70 | [CTSB055X] = "SB055x", | ||
71 | [CTSB073X] = "SB073x", | ||
72 | [CTSB0760] = "SB076x", | ||
73 | [CTUAA] = "UAA", | ||
74 | [CT20K1_UNKNOWN] = "Unknown", | ||
75 | [CTHENDRIX] = "Hendrix", | ||
76 | [CTSB0880] = "SB0880", | ||
77 | }; | ||
78 | |||
79 | static struct { | ||
80 | int (*create)(struct ct_atc *atc, | ||
81 | enum CTALSADEVS device, const char *device_name); | ||
82 | int (*destroy)(void *alsa_dev); | ||
83 | const char *public_name; | ||
84 | } alsa_dev_funcs[NUM_CTALSADEVS] = { | ||
85 | [FRONT] = { .create = ct_alsa_pcm_create, | ||
86 | .destroy = NULL, | ||
87 | .public_name = "Front/WaveIn"}, | ||
88 | [SURROUND] = { .create = ct_alsa_pcm_create, | ||
89 | .destroy = NULL, | ||
90 | .public_name = "Surround"}, | ||
91 | [CLFE] = { .create = ct_alsa_pcm_create, | ||
92 | .destroy = NULL, | ||
93 | .public_name = "Center/LFE"}, | ||
94 | [SIDE] = { .create = ct_alsa_pcm_create, | ||
95 | .destroy = NULL, | ||
96 | .public_name = "Side"}, | ||
97 | [IEC958] = { .create = ct_alsa_pcm_create, | ||
98 | .destroy = NULL, | ||
99 | .public_name = "IEC958 Non-audio"}, | ||
100 | |||
101 | [MIXER] = { .create = ct_alsa_mix_create, | ||
102 | .destroy = NULL, | ||
103 | .public_name = "Mixer"} | ||
104 | }; | ||
105 | |||
106 | typedef int (*create_t)(void *, void **); | ||
107 | typedef int (*destroy_t)(void *); | ||
108 | |||
109 | static struct { | ||
110 | int (*create)(void *hw, void **rmgr); | ||
111 | int (*destroy)(void *mgr); | ||
112 | } rsc_mgr_funcs[NUM_RSCTYP] = { | ||
113 | [SRC] = { .create = (create_t)src_mgr_create, | ||
114 | .destroy = (destroy_t)src_mgr_destroy }, | ||
115 | [SRCIMP] = { .create = (create_t)srcimp_mgr_create, | ||
116 | .destroy = (destroy_t)srcimp_mgr_destroy }, | ||
117 | [AMIXER] = { .create = (create_t)amixer_mgr_create, | ||
118 | .destroy = (destroy_t)amixer_mgr_destroy }, | ||
119 | [SUM] = { .create = (create_t)sum_mgr_create, | ||
120 | .destroy = (destroy_t)sum_mgr_destroy }, | ||
121 | [DAIO] = { .create = (create_t)daio_mgr_create, | ||
122 | .destroy = (destroy_t)daio_mgr_destroy } | ||
123 | }; | ||
124 | |||
125 | static int | ||
126 | atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
127 | |||
128 | /* * | ||
129 | * Only mono and interleaved modes are supported now. | ||
130 | * Always allocates a contiguous channel block. | ||
131 | * */ | ||
132 | |||
133 | static int ct_map_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
134 | { | ||
135 | struct snd_pcm_runtime *runtime; | ||
136 | struct ct_vm *vm; | ||
137 | |||
138 | if (NULL == apcm->substream) | ||
139 | return 0; | ||
140 | |||
141 | runtime = apcm->substream->runtime; | ||
142 | vm = atc->vm; | ||
143 | |||
144 | apcm->vm_block = vm->map(vm, apcm->substream, runtime->dma_bytes); | ||
145 | |||
146 | if (NULL == apcm->vm_block) | ||
147 | return -ENOENT; | ||
148 | |||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | static void ct_unmap_audio_buffer(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
153 | { | ||
154 | struct ct_vm *vm; | ||
155 | |||
156 | if (NULL == apcm->vm_block) | ||
157 | return; | ||
158 | |||
159 | vm = atc->vm; | ||
160 | |||
161 | vm->unmap(vm, apcm->vm_block); | ||
162 | |||
163 | apcm->vm_block = NULL; | ||
164 | } | ||
165 | |||
166 | static unsigned long atc_get_ptp_phys(struct ct_atc *atc, int index) | ||
167 | { | ||
168 | struct ct_vm *vm; | ||
169 | void *kvirt_addr; | ||
170 | unsigned long phys_addr; | ||
171 | |||
172 | vm = atc->vm; | ||
173 | kvirt_addr = vm->get_ptp_virt(vm, index); | ||
174 | if (kvirt_addr == NULL) | ||
175 | phys_addr = (~0UL); | ||
176 | else | ||
177 | phys_addr = virt_to_phys(kvirt_addr); | ||
178 | |||
179 | return phys_addr; | ||
180 | } | ||
181 | |||
182 | static unsigned int convert_format(snd_pcm_format_t snd_format) | ||
183 | { | ||
184 | switch (snd_format) { | ||
185 | case SNDRV_PCM_FORMAT_U8: | ||
186 | return SRC_SF_U8; | ||
187 | case SNDRV_PCM_FORMAT_S16_LE: | ||
188 | return SRC_SF_S16; | ||
189 | case SNDRV_PCM_FORMAT_S24_3LE: | ||
190 | return SRC_SF_S24; | ||
191 | case SNDRV_PCM_FORMAT_S32_LE: | ||
192 | return SRC_SF_S32; | ||
193 | case SNDRV_PCM_FORMAT_FLOAT_LE: | ||
194 | return SRC_SF_F32; | ||
195 | default: | ||
196 | printk(KERN_ERR "ctxfi: not recognized snd format is %d \n", | ||
197 | snd_format); | ||
198 | return SRC_SF_S16; | ||
199 | } | ||
200 | } | ||
201 | |||
202 | static unsigned int | ||
203 | atc_get_pitch(unsigned int input_rate, unsigned int output_rate) | ||
204 | { | ||
205 | unsigned int pitch; | ||
206 | int b; | ||
207 | |||
208 | /* get pitch and convert to fixed-point 8.24 format. */ | ||
209 | pitch = (input_rate / output_rate) << 24; | ||
210 | input_rate %= output_rate; | ||
211 | input_rate /= 100; | ||
212 | output_rate /= 100; | ||
213 | for (b = 31; ((b >= 0) && !(input_rate >> b)); ) | ||
214 | b--; | ||
215 | |||
216 | if (b >= 0) { | ||
217 | input_rate <<= (31 - b); | ||
218 | input_rate /= output_rate; | ||
219 | b = 24 - (31 - b); | ||
220 | if (b >= 0) | ||
221 | input_rate <<= b; | ||
222 | else | ||
223 | input_rate >>= -b; | ||
224 | |||
225 | pitch |= input_rate; | ||
226 | } | ||
227 | |||
228 | return pitch; | ||
229 | } | ||
230 | |||
231 | static int select_rom(unsigned int pitch) | ||
232 | { | ||
233 | if ((pitch > 0x00428f5c) && (pitch < 0x01b851ec)) { | ||
234 | /* 0.26 <= pitch <= 1.72 */ | ||
235 | return 1; | ||
236 | } else if ((0x01d66666 == pitch) || (0x01d66667 == pitch)) { | ||
237 | /* pitch == 1.8375 */ | ||
238 | return 2; | ||
239 | } else if (0x02000000 == pitch) { | ||
240 | /* pitch == 2 */ | ||
241 | return 3; | ||
242 | } else if ((pitch >= 0x0) && (pitch <= 0x08000000)) { | ||
243 | /* 0 <= pitch <= 8 */ | ||
244 | return 0; | ||
245 | } else { | ||
246 | return -ENOENT; | ||
247 | } | ||
248 | } | ||
249 | |||
250 | static int atc_pcm_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
251 | { | ||
252 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
253 | struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; | ||
254 | struct src_desc desc = {0}; | ||
255 | struct amixer_desc mix_dsc = {0}; | ||
256 | struct src *src; | ||
257 | struct amixer *amixer; | ||
258 | int err; | ||
259 | int n_amixer = apcm->substream->runtime->channels, i = 0; | ||
260 | int device = apcm->substream->pcm->device; | ||
261 | unsigned int pitch; | ||
262 | unsigned long flags; | ||
263 | |||
264 | if (NULL != apcm->src) { | ||
265 | /* Prepared pcm playback */ | ||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | /* first release old resources */ | ||
270 | atc->pcm_release_resources(atc, apcm); | ||
271 | |||
272 | /* Get SRC resource */ | ||
273 | desc.multi = apcm->substream->runtime->channels; | ||
274 | desc.msr = atc->msr; | ||
275 | desc.mode = MEMRD; | ||
276 | err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); | ||
277 | if (err) | ||
278 | goto error1; | ||
279 | |||
280 | pitch = atc_get_pitch(apcm->substream->runtime->rate, | ||
281 | (atc->rsr * atc->msr)); | ||
282 | src = apcm->src; | ||
283 | src->ops->set_pitch(src, pitch); | ||
284 | src->ops->set_rom(src, select_rom(pitch)); | ||
285 | src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); | ||
286 | src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); | ||
287 | |||
288 | /* Get AMIXER resource */ | ||
289 | n_amixer = (n_amixer < 2) ? 2 : n_amixer; | ||
290 | apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); | ||
291 | if (NULL == apcm->amixers) { | ||
292 | err = -ENOMEM; | ||
293 | goto error1; | ||
294 | } | ||
295 | mix_dsc.msr = atc->msr; | ||
296 | for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { | ||
297 | err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, | ||
298 | (struct amixer **)&apcm->amixers[i]); | ||
299 | if (err) | ||
300 | goto error1; | ||
301 | |||
302 | apcm->n_amixer++; | ||
303 | } | ||
304 | |||
305 | /* Set up device virtual mem map */ | ||
306 | err = ct_map_audio_buffer(atc, apcm); | ||
307 | if (err < 0) | ||
308 | goto error1; | ||
309 | |||
310 | /* Connect resources */ | ||
311 | src = apcm->src; | ||
312 | for (i = 0; i < n_amixer; i++) { | ||
313 | amixer = apcm->amixers[i]; | ||
314 | spin_lock_irqsave(&atc->atc_lock, flags); | ||
315 | amixer->ops->setup(amixer, &src->rsc, | ||
316 | INIT_VOL, atc->pcm[i+device*2]); | ||
317 | spin_unlock_irqrestore(&atc->atc_lock, flags); | ||
318 | src = src->ops->next_interleave(src); | ||
319 | if (NULL == src) | ||
320 | src = apcm->src; | ||
321 | } | ||
322 | |||
323 | ct_timer_prepare(apcm->timer); | ||
324 | |||
325 | return 0; | ||
326 | |||
327 | error1: | ||
328 | atc_pcm_release_resources(atc, apcm); | ||
329 | return err; | ||
330 | } | ||
331 | |||
332 | static int | ||
333 | atc_pcm_release_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
334 | { | ||
335 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
336 | struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | ||
337 | struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; | ||
338 | struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; | ||
339 | struct srcimp *srcimp; | ||
340 | int i; | ||
341 | |||
342 | if (NULL != apcm->srcimps) { | ||
343 | for (i = 0; i < apcm->n_srcimp; i++) { | ||
344 | srcimp = apcm->srcimps[i]; | ||
345 | srcimp->ops->unmap(srcimp); | ||
346 | srcimp_mgr->put_srcimp(srcimp_mgr, srcimp); | ||
347 | apcm->srcimps[i] = NULL; | ||
348 | } | ||
349 | kfree(apcm->srcimps); | ||
350 | apcm->srcimps = NULL; | ||
351 | } | ||
352 | |||
353 | if (NULL != apcm->srccs) { | ||
354 | for (i = 0; i < apcm->n_srcc; i++) { | ||
355 | src_mgr->put_src(src_mgr, apcm->srccs[i]); | ||
356 | apcm->srccs[i] = NULL; | ||
357 | } | ||
358 | kfree(apcm->srccs); | ||
359 | apcm->srccs = NULL; | ||
360 | } | ||
361 | |||
362 | if (NULL != apcm->amixers) { | ||
363 | for (i = 0; i < apcm->n_amixer; i++) { | ||
364 | amixer_mgr->put_amixer(amixer_mgr, apcm->amixers[i]); | ||
365 | apcm->amixers[i] = NULL; | ||
366 | } | ||
367 | kfree(apcm->amixers); | ||
368 | apcm->amixers = NULL; | ||
369 | } | ||
370 | |||
371 | if (NULL != apcm->mono) { | ||
372 | sum_mgr->put_sum(sum_mgr, apcm->mono); | ||
373 | apcm->mono = NULL; | ||
374 | } | ||
375 | |||
376 | if (NULL != apcm->src) { | ||
377 | src_mgr->put_src(src_mgr, apcm->src); | ||
378 | apcm->src = NULL; | ||
379 | } | ||
380 | |||
381 | if (NULL != apcm->vm_block) { | ||
382 | /* Undo device virtual mem map */ | ||
383 | ct_unmap_audio_buffer(atc, apcm); | ||
384 | apcm->vm_block = NULL; | ||
385 | } | ||
386 | |||
387 | return 0; | ||
388 | } | ||
389 | |||
390 | static int atc_pcm_playback_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
391 | { | ||
392 | unsigned int max_cisz; | ||
393 | struct src *src = apcm->src; | ||
394 | |||
395 | if (apcm->started) | ||
396 | return 0; | ||
397 | apcm->started = 1; | ||
398 | |||
399 | max_cisz = src->multi * src->rsc.msr; | ||
400 | max_cisz = 0x80 * (max_cisz < 8 ? max_cisz : 8); | ||
401 | |||
402 | src->ops->set_sa(src, apcm->vm_block->addr); | ||
403 | src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); | ||
404 | src->ops->set_ca(src, apcm->vm_block->addr + max_cisz); | ||
405 | src->ops->set_cisz(src, max_cisz); | ||
406 | |||
407 | src->ops->set_bm(src, 1); | ||
408 | src->ops->set_state(src, SRC_STATE_INIT); | ||
409 | src->ops->commit_write(src); | ||
410 | |||
411 | ct_timer_start(apcm->timer); | ||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static int atc_pcm_stop(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
416 | { | ||
417 | struct src *src; | ||
418 | int i; | ||
419 | |||
420 | ct_timer_stop(apcm->timer); | ||
421 | |||
422 | src = apcm->src; | ||
423 | src->ops->set_bm(src, 0); | ||
424 | src->ops->set_state(src, SRC_STATE_OFF); | ||
425 | src->ops->commit_write(src); | ||
426 | |||
427 | if (NULL != apcm->srccs) { | ||
428 | for (i = 0; i < apcm->n_srcc; i++) { | ||
429 | src = apcm->srccs[i]; | ||
430 | src->ops->set_bm(src, 0); | ||
431 | src->ops->set_state(src, SRC_STATE_OFF); | ||
432 | src->ops->commit_write(src); | ||
433 | } | ||
434 | } | ||
435 | |||
436 | apcm->started = 0; | ||
437 | |||
438 | return 0; | ||
439 | } | ||
440 | |||
441 | static int | ||
442 | atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
443 | { | ||
444 | struct src *src = apcm->src; | ||
445 | u32 size, max_cisz; | ||
446 | int position; | ||
447 | |||
448 | if (!src) | ||
449 | return 0; | ||
450 | position = src->ops->get_ca(src); | ||
451 | |||
452 | size = apcm->vm_block->size; | ||
453 | max_cisz = src->multi * src->rsc.msr; | ||
454 | max_cisz = 128 * (max_cisz < 8 ? max_cisz : 8); | ||
455 | |||
456 | return (position + size - max_cisz - apcm->vm_block->addr) % size; | ||
457 | } | ||
458 | |||
459 | struct src_node_conf_t { | ||
460 | unsigned int pitch; | ||
461 | unsigned int msr:8; | ||
462 | unsigned int mix_msr:8; | ||
463 | unsigned int imp_msr:8; | ||
464 | unsigned int vo:1; | ||
465 | }; | ||
466 | |||
467 | static void setup_src_node_conf(struct ct_atc *atc, struct ct_atc_pcm *apcm, | ||
468 | struct src_node_conf_t *conf, int *n_srcc) | ||
469 | { | ||
470 | unsigned int pitch; | ||
471 | |||
472 | /* get pitch and convert to fixed-point 8.24 format. */ | ||
473 | pitch = atc_get_pitch((atc->rsr * atc->msr), | ||
474 | apcm->substream->runtime->rate); | ||
475 | *n_srcc = 0; | ||
476 | |||
477 | if (1 == atc->msr) { | ||
478 | *n_srcc = apcm->substream->runtime->channels; | ||
479 | conf[0].pitch = pitch; | ||
480 | conf[0].mix_msr = conf[0].imp_msr = conf[0].msr = 1; | ||
481 | conf[0].vo = 1; | ||
482 | } else if (2 == atc->msr) { | ||
483 | if (0x8000000 < pitch) { | ||
484 | /* Need two-stage SRCs, SRCIMPs and | ||
485 | * AMIXERs for converting format */ | ||
486 | conf[0].pitch = (atc->msr << 24); | ||
487 | conf[0].msr = conf[0].mix_msr = 1; | ||
488 | conf[0].imp_msr = atc->msr; | ||
489 | conf[0].vo = 0; | ||
490 | conf[1].pitch = atc_get_pitch(atc->rsr, | ||
491 | apcm->substream->runtime->rate); | ||
492 | conf[1].msr = conf[1].mix_msr = conf[1].imp_msr = 1; | ||
493 | conf[1].vo = 1; | ||
494 | *n_srcc = apcm->substream->runtime->channels * 2; | ||
495 | } else if (0x1000000 < pitch) { | ||
496 | /* Need one-stage SRCs, SRCIMPs and | ||
497 | * AMIXERs for converting format */ | ||
498 | conf[0].pitch = pitch; | ||
499 | conf[0].msr = conf[0].mix_msr | ||
500 | = conf[0].imp_msr = atc->msr; | ||
501 | conf[0].vo = 1; | ||
502 | *n_srcc = apcm->substream->runtime->channels; | ||
503 | } | ||
504 | } | ||
505 | } | ||
506 | |||
507 | static int | ||
508 | atc_pcm_capture_get_resources(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
509 | { | ||
510 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
511 | struct srcimp_mgr *srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | ||
512 | struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; | ||
513 | struct sum_mgr *sum_mgr = atc->rsc_mgrs[SUM]; | ||
514 | struct src_desc src_dsc = {0}; | ||
515 | struct src *src; | ||
516 | struct srcimp_desc srcimp_dsc = {0}; | ||
517 | struct srcimp *srcimp; | ||
518 | struct amixer_desc mix_dsc = {0}; | ||
519 | struct sum_desc sum_dsc = {0}; | ||
520 | unsigned int pitch; | ||
521 | int multi, err, i; | ||
522 | int n_srcimp, n_amixer, n_srcc, n_sum; | ||
523 | struct src_node_conf_t src_node_conf[2] = {{0} }; | ||
524 | |||
525 | /* first release old resources */ | ||
526 | atc_pcm_release_resources(atc, apcm); | ||
527 | |||
528 | /* The numbers of converting SRCs and SRCIMPs should be determined | ||
529 | * by pitch value. */ | ||
530 | |||
531 | multi = apcm->substream->runtime->channels; | ||
532 | |||
533 | /* get pitch and convert to fixed-point 8.24 format. */ | ||
534 | pitch = atc_get_pitch((atc->rsr * atc->msr), | ||
535 | apcm->substream->runtime->rate); | ||
536 | |||
537 | setup_src_node_conf(atc, apcm, src_node_conf, &n_srcc); | ||
538 | n_sum = (1 == multi) ? 1 : 0; | ||
539 | n_amixer = n_sum * 2 + n_srcc; | ||
540 | n_srcimp = n_srcc; | ||
541 | if ((multi > 1) && (0x8000000 >= pitch)) { | ||
542 | /* Need extra AMIXERs and SRCIMPs for special treatment | ||
543 | * of interleaved recording of conjugate channels */ | ||
544 | n_amixer += multi * atc->msr; | ||
545 | n_srcimp += multi * atc->msr; | ||
546 | } else { | ||
547 | n_srcimp += multi; | ||
548 | } | ||
549 | |||
550 | if (n_srcc) { | ||
551 | apcm->srccs = kzalloc(sizeof(void *)*n_srcc, GFP_KERNEL); | ||
552 | if (NULL == apcm->srccs) | ||
553 | return -ENOMEM; | ||
554 | } | ||
555 | if (n_amixer) { | ||
556 | apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); | ||
557 | if (NULL == apcm->amixers) { | ||
558 | err = -ENOMEM; | ||
559 | goto error1; | ||
560 | } | ||
561 | } | ||
562 | apcm->srcimps = kzalloc(sizeof(void *)*n_srcimp, GFP_KERNEL); | ||
563 | if (NULL == apcm->srcimps) { | ||
564 | err = -ENOMEM; | ||
565 | goto error1; | ||
566 | } | ||
567 | |||
568 | /* Allocate SRCs for sample rate conversion if needed */ | ||
569 | src_dsc.multi = 1; | ||
570 | src_dsc.mode = ARCRW; | ||
571 | for (i = 0, apcm->n_srcc = 0; i < n_srcc; i++) { | ||
572 | src_dsc.msr = src_node_conf[i/multi].msr; | ||
573 | err = src_mgr->get_src(src_mgr, &src_dsc, | ||
574 | (struct src **)&apcm->srccs[i]); | ||
575 | if (err) | ||
576 | goto error1; | ||
577 | |||
578 | src = apcm->srccs[i]; | ||
579 | pitch = src_node_conf[i/multi].pitch; | ||
580 | src->ops->set_pitch(src, pitch); | ||
581 | src->ops->set_rom(src, select_rom(pitch)); | ||
582 | src->ops->set_vo(src, src_node_conf[i/multi].vo); | ||
583 | |||
584 | apcm->n_srcc++; | ||
585 | } | ||
586 | |||
587 | /* Allocate AMIXERs for routing SRCs of conversion if needed */ | ||
588 | for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { | ||
589 | if (i < (n_sum*2)) | ||
590 | mix_dsc.msr = atc->msr; | ||
591 | else if (i < (n_sum*2+n_srcc)) | ||
592 | mix_dsc.msr = src_node_conf[(i-n_sum*2)/multi].mix_msr; | ||
593 | else | ||
594 | mix_dsc.msr = 1; | ||
595 | |||
596 | err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, | ||
597 | (struct amixer **)&apcm->amixers[i]); | ||
598 | if (err) | ||
599 | goto error1; | ||
600 | |||
601 | apcm->n_amixer++; | ||
602 | } | ||
603 | |||
604 | /* Allocate a SUM resource to mix all input channels together */ | ||
605 | sum_dsc.msr = atc->msr; | ||
606 | err = sum_mgr->get_sum(sum_mgr, &sum_dsc, (struct sum **)&apcm->mono); | ||
607 | if (err) | ||
608 | goto error1; | ||
609 | |||
610 | pitch = atc_get_pitch((atc->rsr * atc->msr), | ||
611 | apcm->substream->runtime->rate); | ||
612 | /* Allocate SRCIMP resources */ | ||
613 | for (i = 0, apcm->n_srcimp = 0; i < n_srcimp; i++) { | ||
614 | if (i < (n_srcc)) | ||
615 | srcimp_dsc.msr = src_node_conf[i/multi].imp_msr; | ||
616 | else if (1 == multi) | ||
617 | srcimp_dsc.msr = (pitch <= 0x8000000) ? atc->msr : 1; | ||
618 | else | ||
619 | srcimp_dsc.msr = 1; | ||
620 | |||
621 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, &srcimp); | ||
622 | if (err) | ||
623 | goto error1; | ||
624 | |||
625 | apcm->srcimps[i] = srcimp; | ||
626 | apcm->n_srcimp++; | ||
627 | } | ||
628 | |||
629 | /* Allocate a SRC for writing data to host memory */ | ||
630 | src_dsc.multi = apcm->substream->runtime->channels; | ||
631 | src_dsc.msr = 1; | ||
632 | src_dsc.mode = MEMWR; | ||
633 | err = src_mgr->get_src(src_mgr, &src_dsc, (struct src **)&apcm->src); | ||
634 | if (err) | ||
635 | goto error1; | ||
636 | |||
637 | src = apcm->src; | ||
638 | src->ops->set_pitch(src, pitch); | ||
639 | |||
640 | /* Set up device virtual mem map */ | ||
641 | err = ct_map_audio_buffer(atc, apcm); | ||
642 | if (err < 0) | ||
643 | goto error1; | ||
644 | |||
645 | return 0; | ||
646 | |||
647 | error1: | ||
648 | atc_pcm_release_resources(atc, apcm); | ||
649 | return err; | ||
650 | } | ||
651 | |||
652 | static int atc_pcm_capture_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
653 | { | ||
654 | struct src *src; | ||
655 | struct amixer *amixer; | ||
656 | struct srcimp *srcimp; | ||
657 | struct ct_mixer *mixer = atc->mixer; | ||
658 | struct sum *mono; | ||
659 | struct rsc *out_ports[8] = {NULL}; | ||
660 | int err, i, j, n_sum, multi; | ||
661 | unsigned int pitch; | ||
662 | int mix_base = 0, imp_base = 0; | ||
663 | |||
664 | if (NULL != apcm->src) { | ||
665 | /* Prepared pcm capture */ | ||
666 | return 0; | ||
667 | } | ||
668 | |||
669 | /* Get needed resources. */ | ||
670 | err = atc_pcm_capture_get_resources(atc, apcm); | ||
671 | if (err) | ||
672 | return err; | ||
673 | |||
674 | /* Connect resources */ | ||
675 | mixer->get_output_ports(mixer, MIX_PCMO_FRONT, | ||
676 | &out_ports[0], &out_ports[1]); | ||
677 | |||
678 | multi = apcm->substream->runtime->channels; | ||
679 | if (1 == multi) { | ||
680 | mono = apcm->mono; | ||
681 | for (i = 0; i < 2; i++) { | ||
682 | amixer = apcm->amixers[i]; | ||
683 | amixer->ops->setup(amixer, out_ports[i], | ||
684 | MONO_SUM_SCALE, mono); | ||
685 | } | ||
686 | out_ports[0] = &mono->rsc; | ||
687 | n_sum = 1; | ||
688 | mix_base = n_sum * 2; | ||
689 | } | ||
690 | |||
691 | for (i = 0; i < apcm->n_srcc; i++) { | ||
692 | src = apcm->srccs[i]; | ||
693 | srcimp = apcm->srcimps[imp_base+i]; | ||
694 | amixer = apcm->amixers[mix_base+i]; | ||
695 | srcimp->ops->map(srcimp, src, out_ports[i%multi]); | ||
696 | amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); | ||
697 | out_ports[i%multi] = &amixer->rsc; | ||
698 | } | ||
699 | |||
700 | pitch = atc_get_pitch((atc->rsr * atc->msr), | ||
701 | apcm->substream->runtime->rate); | ||
702 | |||
703 | if ((multi > 1) && (pitch <= 0x8000000)) { | ||
704 | /* Special connection for interleaved | ||
705 | * recording with conjugate channels */ | ||
706 | for (i = 0; i < multi; i++) { | ||
707 | out_ports[i]->ops->master(out_ports[i]); | ||
708 | for (j = 0; j < atc->msr; j++) { | ||
709 | amixer = apcm->amixers[apcm->n_srcc+j*multi+i]; | ||
710 | amixer->ops->set_input(amixer, out_ports[i]); | ||
711 | amixer->ops->set_scale(amixer, INIT_VOL); | ||
712 | amixer->ops->set_sum(amixer, NULL); | ||
713 | amixer->ops->commit_raw_write(amixer); | ||
714 | out_ports[i]->ops->next_conj(out_ports[i]); | ||
715 | |||
716 | srcimp = apcm->srcimps[apcm->n_srcc+j*multi+i]; | ||
717 | srcimp->ops->map(srcimp, apcm->src, | ||
718 | &amixer->rsc); | ||
719 | } | ||
720 | } | ||
721 | } else { | ||
722 | for (i = 0; i < multi; i++) { | ||
723 | srcimp = apcm->srcimps[apcm->n_srcc+i]; | ||
724 | srcimp->ops->map(srcimp, apcm->src, out_ports[i]); | ||
725 | } | ||
726 | } | ||
727 | |||
728 | ct_timer_prepare(apcm->timer); | ||
729 | |||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | static int atc_pcm_capture_start(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
734 | { | ||
735 | struct src *src; | ||
736 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
737 | int i, multi; | ||
738 | |||
739 | if (apcm->started) | ||
740 | return 0; | ||
741 | |||
742 | apcm->started = 1; | ||
743 | multi = apcm->substream->runtime->channels; | ||
744 | /* Set up converting SRCs */ | ||
745 | for (i = 0; i < apcm->n_srcc; i++) { | ||
746 | src = apcm->srccs[i]; | ||
747 | src->ops->set_pm(src, ((i%multi) != (multi-1))); | ||
748 | src_mgr->src_disable(src_mgr, src); | ||
749 | } | ||
750 | |||
751 | /* Set up recording SRC */ | ||
752 | src = apcm->src; | ||
753 | src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); | ||
754 | src->ops->set_sa(src, apcm->vm_block->addr); | ||
755 | src->ops->set_la(src, apcm->vm_block->addr + apcm->vm_block->size); | ||
756 | src->ops->set_ca(src, apcm->vm_block->addr); | ||
757 | src_mgr->src_disable(src_mgr, src); | ||
758 | |||
759 | /* Disable relevant SRCs firstly */ | ||
760 | src_mgr->commit_write(src_mgr); | ||
761 | |||
762 | /* Enable SRCs respectively */ | ||
763 | for (i = 0; i < apcm->n_srcc; i++) { | ||
764 | src = apcm->srccs[i]; | ||
765 | src->ops->set_state(src, SRC_STATE_RUN); | ||
766 | src->ops->commit_write(src); | ||
767 | src_mgr->src_enable_s(src_mgr, src); | ||
768 | } | ||
769 | src = apcm->src; | ||
770 | src->ops->set_bm(src, 1); | ||
771 | src->ops->set_state(src, SRC_STATE_RUN); | ||
772 | src->ops->commit_write(src); | ||
773 | src_mgr->src_enable_s(src_mgr, src); | ||
774 | |||
775 | /* Enable relevant SRCs synchronously */ | ||
776 | src_mgr->commit_write(src_mgr); | ||
777 | |||
778 | ct_timer_start(apcm->timer); | ||
779 | return 0; | ||
780 | } | ||
781 | |||
782 | static int | ||
783 | atc_pcm_capture_position(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
784 | { | ||
785 | struct src *src = apcm->src; | ||
786 | |||
787 | if (!src) | ||
788 | return 0; | ||
789 | return src->ops->get_ca(src) - apcm->vm_block->addr; | ||
790 | } | ||
791 | |||
792 | static int spdif_passthru_playback_get_resources(struct ct_atc *atc, | ||
793 | struct ct_atc_pcm *apcm) | ||
794 | { | ||
795 | struct src_mgr *src_mgr = atc->rsc_mgrs[SRC]; | ||
796 | struct amixer_mgr *amixer_mgr = atc->rsc_mgrs[AMIXER]; | ||
797 | struct src_desc desc = {0}; | ||
798 | struct amixer_desc mix_dsc = {0}; | ||
799 | struct src *src; | ||
800 | int err; | ||
801 | int n_amixer = apcm->substream->runtime->channels, i; | ||
802 | unsigned int pitch, rsr = atc->pll_rate; | ||
803 | |||
804 | /* first release old resources */ | ||
805 | atc_pcm_release_resources(atc, apcm); | ||
806 | |||
807 | /* Get SRC resource */ | ||
808 | desc.multi = apcm->substream->runtime->channels; | ||
809 | desc.msr = 1; | ||
810 | while (apcm->substream->runtime->rate > (rsr * desc.msr)) | ||
811 | desc.msr <<= 1; | ||
812 | |||
813 | desc.mode = MEMRD; | ||
814 | err = src_mgr->get_src(src_mgr, &desc, (struct src **)&apcm->src); | ||
815 | if (err) | ||
816 | goto error1; | ||
817 | |||
818 | pitch = atc_get_pitch(apcm->substream->runtime->rate, (rsr * desc.msr)); | ||
819 | src = apcm->src; | ||
820 | src->ops->set_pitch(src, pitch); | ||
821 | src->ops->set_rom(src, select_rom(pitch)); | ||
822 | src->ops->set_sf(src, convert_format(apcm->substream->runtime->format)); | ||
823 | src->ops->set_pm(src, (src->ops->next_interleave(src) != NULL)); | ||
824 | src->ops->set_bp(src, 1); | ||
825 | |||
826 | /* Get AMIXER resource */ | ||
827 | n_amixer = (n_amixer < 2) ? 2 : n_amixer; | ||
828 | apcm->amixers = kzalloc(sizeof(void *)*n_amixer, GFP_KERNEL); | ||
829 | if (NULL == apcm->amixers) { | ||
830 | err = -ENOMEM; | ||
831 | goto error1; | ||
832 | } | ||
833 | mix_dsc.msr = desc.msr; | ||
834 | for (i = 0, apcm->n_amixer = 0; i < n_amixer; i++) { | ||
835 | err = amixer_mgr->get_amixer(amixer_mgr, &mix_dsc, | ||
836 | (struct amixer **)&apcm->amixers[i]); | ||
837 | if (err) | ||
838 | goto error1; | ||
839 | |||
840 | apcm->n_amixer++; | ||
841 | } | ||
842 | |||
843 | /* Set up device virtual mem map */ | ||
844 | err = ct_map_audio_buffer(atc, apcm); | ||
845 | if (err < 0) | ||
846 | goto error1; | ||
847 | |||
848 | return 0; | ||
849 | |||
850 | error1: | ||
851 | atc_pcm_release_resources(atc, apcm); | ||
852 | return err; | ||
853 | } | ||
854 | |||
855 | static int atc_pll_init(struct ct_atc *atc, int rate) | ||
856 | { | ||
857 | struct hw *hw = atc->hw; | ||
858 | int err; | ||
859 | err = hw->pll_init(hw, rate); | ||
860 | atc->pll_rate = err ? 0 : rate; | ||
861 | return err; | ||
862 | } | ||
863 | |||
864 | static int | ||
865 | spdif_passthru_playback_setup(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
866 | { | ||
867 | struct dao *dao = container_of(atc->daios[SPDIFOO], struct dao, daio); | ||
868 | unsigned long flags; | ||
869 | unsigned int rate = apcm->substream->runtime->rate; | ||
870 | unsigned int status; | ||
871 | int err; | ||
872 | unsigned char iec958_con_fs; | ||
873 | |||
874 | switch (rate) { | ||
875 | case 48000: | ||
876 | iec958_con_fs = IEC958_AES3_CON_FS_48000; | ||
877 | break; | ||
878 | case 44100: | ||
879 | iec958_con_fs = IEC958_AES3_CON_FS_44100; | ||
880 | break; | ||
881 | case 32000: | ||
882 | iec958_con_fs = IEC958_AES3_CON_FS_32000; | ||
883 | break; | ||
884 | default: | ||
885 | return -ENOENT; | ||
886 | } | ||
887 | |||
888 | spin_lock_irqsave(&atc->atc_lock, flags); | ||
889 | dao->ops->get_spos(dao, &status); | ||
890 | if (((status >> 24) & IEC958_AES3_CON_FS) != iec958_con_fs) { | ||
891 | status &= ((~IEC958_AES3_CON_FS) << 24); | ||
892 | status |= (iec958_con_fs << 24); | ||
893 | dao->ops->set_spos(dao, status); | ||
894 | dao->ops->commit_write(dao); | ||
895 | } | ||
896 | if ((rate != atc->pll_rate) && (32000 != rate)) | ||
897 | err = atc_pll_init(atc, rate); | ||
898 | spin_unlock_irqrestore(&atc->atc_lock, flags); | ||
899 | |||
900 | return err; | ||
901 | } | ||
902 | |||
903 | static int | ||
904 | spdif_passthru_playback_prepare(struct ct_atc *atc, struct ct_atc_pcm *apcm) | ||
905 | { | ||
906 | struct src *src; | ||
907 | struct amixer *amixer; | ||
908 | struct dao *dao; | ||
909 | int err; | ||
910 | int i; | ||
911 | unsigned long flags; | ||
912 | |||
913 | if (NULL != apcm->src) | ||
914 | return 0; | ||
915 | |||
916 | /* Configure SPDIFOO and PLL to passthrough mode; | ||
917 | * determine pll_rate. */ | ||
918 | err = spdif_passthru_playback_setup(atc, apcm); | ||
919 | if (err) | ||
920 | return err; | ||
921 | |||
922 | /* Get needed resources. */ | ||
923 | err = spdif_passthru_playback_get_resources(atc, apcm); | ||
924 | if (err) | ||
925 | return err; | ||
926 | |||
927 | /* Connect resources */ | ||
928 | src = apcm->src; | ||
929 | for (i = 0; i < apcm->n_amixer; i++) { | ||
930 | amixer = apcm->amixers[i]; | ||
931 | amixer->ops->setup(amixer, &src->rsc, INIT_VOL, NULL); | ||
932 | src = src->ops->next_interleave(src); | ||
933 | if (NULL == src) | ||
934 | src = apcm->src; | ||
935 | } | ||
936 | /* Connect to SPDIFOO */ | ||
937 | spin_lock_irqsave(&atc->atc_lock, flags); | ||
938 | dao = container_of(atc->daios[SPDIFOO], struct dao, daio); | ||
939 | amixer = apcm->amixers[0]; | ||
940 | dao->ops->set_left_input(dao, &amixer->rsc); | ||
941 | amixer = apcm->amixers[1]; | ||
942 | dao->ops->set_right_input(dao, &amixer->rsc); | ||
943 | spin_unlock_irqrestore(&atc->atc_lock, flags); | ||
944 | |||
945 | ct_timer_prepare(apcm->timer); | ||
946 | |||
947 | return 0; | ||
948 | } | ||
949 | |||
950 | static int atc_select_line_in(struct ct_atc *atc) | ||
951 | { | ||
952 | struct hw *hw = atc->hw; | ||
953 | struct ct_mixer *mixer = atc->mixer; | ||
954 | struct src *src; | ||
955 | |||
956 | if (hw->is_adc_source_selected(hw, ADC_LINEIN)) | ||
957 | return 0; | ||
958 | |||
959 | mixer->set_input_left(mixer, MIX_MIC_IN, NULL); | ||
960 | mixer->set_input_right(mixer, MIX_MIC_IN, NULL); | ||
961 | |||
962 | hw->select_adc_source(hw, ADC_LINEIN); | ||
963 | |||
964 | src = atc->srcs[2]; | ||
965 | mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); | ||
966 | src = atc->srcs[3]; | ||
967 | mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); | ||
968 | |||
969 | return 0; | ||
970 | } | ||
971 | |||
972 | static int atc_select_mic_in(struct ct_atc *atc) | ||
973 | { | ||
974 | struct hw *hw = atc->hw; | ||
975 | struct ct_mixer *mixer = atc->mixer; | ||
976 | struct src *src; | ||
977 | |||
978 | if (hw->is_adc_source_selected(hw, ADC_MICIN)) | ||
979 | return 0; | ||
980 | |||
981 | mixer->set_input_left(mixer, MIX_LINE_IN, NULL); | ||
982 | mixer->set_input_right(mixer, MIX_LINE_IN, NULL); | ||
983 | |||
984 | hw->select_adc_source(hw, ADC_MICIN); | ||
985 | |||
986 | src = atc->srcs[2]; | ||
987 | mixer->set_input_left(mixer, MIX_MIC_IN, &src->rsc); | ||
988 | src = atc->srcs[3]; | ||
989 | mixer->set_input_right(mixer, MIX_MIC_IN, &src->rsc); | ||
990 | |||
991 | return 0; | ||
992 | } | ||
993 | |||
994 | static int atc_have_digit_io_switch(struct ct_atc *atc) | ||
995 | { | ||
996 | struct hw *hw = atc->hw; | ||
997 | |||
998 | return hw->have_digit_io_switch(hw); | ||
999 | } | ||
1000 | |||
1001 | static int atc_select_digit_io(struct ct_atc *atc) | ||
1002 | { | ||
1003 | struct hw *hw = atc->hw; | ||
1004 | |||
1005 | if (hw->is_adc_source_selected(hw, ADC_NONE)) | ||
1006 | return 0; | ||
1007 | |||
1008 | hw->select_adc_source(hw, ADC_NONE); | ||
1009 | |||
1010 | return 0; | ||
1011 | } | ||
1012 | |||
1013 | static int atc_daio_unmute(struct ct_atc *atc, unsigned char state, int type) | ||
1014 | { | ||
1015 | struct daio_mgr *daio_mgr = atc->rsc_mgrs[DAIO]; | ||
1016 | |||
1017 | if (state) | ||
1018 | daio_mgr->daio_enable(daio_mgr, atc->daios[type]); | ||
1019 | else | ||
1020 | daio_mgr->daio_disable(daio_mgr, atc->daios[type]); | ||
1021 | |||
1022 | daio_mgr->commit_write(daio_mgr); | ||
1023 | |||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static int | ||
1028 | atc_dao_get_status(struct ct_atc *atc, unsigned int *status, int type) | ||
1029 | { | ||
1030 | struct dao *dao = container_of(atc->daios[type], struct dao, daio); | ||
1031 | return dao->ops->get_spos(dao, status); | ||
1032 | } | ||
1033 | |||
1034 | static int | ||
1035 | atc_dao_set_status(struct ct_atc *atc, unsigned int status, int type) | ||
1036 | { | ||
1037 | struct dao *dao = container_of(atc->daios[type], struct dao, daio); | ||
1038 | |||
1039 | dao->ops->set_spos(dao, status); | ||
1040 | dao->ops->commit_write(dao); | ||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | static int atc_line_front_unmute(struct ct_atc *atc, unsigned char state) | ||
1045 | { | ||
1046 | return atc_daio_unmute(atc, state, LINEO1); | ||
1047 | } | ||
1048 | |||
1049 | static int atc_line_surround_unmute(struct ct_atc *atc, unsigned char state) | ||
1050 | { | ||
1051 | return atc_daio_unmute(atc, state, LINEO4); | ||
1052 | } | ||
1053 | |||
1054 | static int atc_line_clfe_unmute(struct ct_atc *atc, unsigned char state) | ||
1055 | { | ||
1056 | return atc_daio_unmute(atc, state, LINEO3); | ||
1057 | } | ||
1058 | |||
1059 | static int atc_line_rear_unmute(struct ct_atc *atc, unsigned char state) | ||
1060 | { | ||
1061 | return atc_daio_unmute(atc, state, LINEO2); | ||
1062 | } | ||
1063 | |||
1064 | static int atc_line_in_unmute(struct ct_atc *atc, unsigned char state) | ||
1065 | { | ||
1066 | return atc_daio_unmute(atc, state, LINEIM); | ||
1067 | } | ||
1068 | |||
1069 | static int atc_spdif_out_unmute(struct ct_atc *atc, unsigned char state) | ||
1070 | { | ||
1071 | return atc_daio_unmute(atc, state, SPDIFOO); | ||
1072 | } | ||
1073 | |||
1074 | static int atc_spdif_in_unmute(struct ct_atc *atc, unsigned char state) | ||
1075 | { | ||
1076 | return atc_daio_unmute(atc, state, SPDIFIO); | ||
1077 | } | ||
1078 | |||
1079 | static int atc_spdif_out_get_status(struct ct_atc *atc, unsigned int *status) | ||
1080 | { | ||
1081 | return atc_dao_get_status(atc, status, SPDIFOO); | ||
1082 | } | ||
1083 | |||
1084 | static int atc_spdif_out_set_status(struct ct_atc *atc, unsigned int status) | ||
1085 | { | ||
1086 | return atc_dao_set_status(atc, status, SPDIFOO); | ||
1087 | } | ||
1088 | |||
1089 | static int atc_spdif_out_passthru(struct ct_atc *atc, unsigned char state) | ||
1090 | { | ||
1091 | unsigned long flags; | ||
1092 | struct dao_desc da_dsc = {0}; | ||
1093 | struct dao *dao; | ||
1094 | int err; | ||
1095 | struct ct_mixer *mixer = atc->mixer; | ||
1096 | struct rsc *rscs[2] = {NULL}; | ||
1097 | unsigned int spos = 0; | ||
1098 | |||
1099 | spin_lock_irqsave(&atc->atc_lock, flags); | ||
1100 | dao = container_of(atc->daios[SPDIFOO], struct dao, daio); | ||
1101 | da_dsc.msr = state ? 1 : atc->msr; | ||
1102 | da_dsc.passthru = state ? 1 : 0; | ||
1103 | err = dao->ops->reinit(dao, &da_dsc); | ||
1104 | if (state) { | ||
1105 | spos = IEC958_DEFAULT_CON; | ||
1106 | } else { | ||
1107 | mixer->get_output_ports(mixer, MIX_SPDIF_OUT, | ||
1108 | &rscs[0], &rscs[1]); | ||
1109 | dao->ops->set_left_input(dao, rscs[0]); | ||
1110 | dao->ops->set_right_input(dao, rscs[1]); | ||
1111 | /* Restore PLL to atc->rsr if needed. */ | ||
1112 | if (atc->pll_rate != atc->rsr) | ||
1113 | err = atc_pll_init(atc, atc->rsr); | ||
1114 | } | ||
1115 | dao->ops->set_spos(dao, spos); | ||
1116 | dao->ops->commit_write(dao); | ||
1117 | spin_unlock_irqrestore(&atc->atc_lock, flags); | ||
1118 | |||
1119 | return err; | ||
1120 | } | ||
1121 | |||
1122 | static int ct_atc_destroy(struct ct_atc *atc) | ||
1123 | { | ||
1124 | struct daio_mgr *daio_mgr; | ||
1125 | struct dao *dao; | ||
1126 | struct dai *dai; | ||
1127 | struct daio *daio; | ||
1128 | struct sum_mgr *sum_mgr; | ||
1129 | struct src_mgr *src_mgr; | ||
1130 | struct srcimp_mgr *srcimp_mgr; | ||
1131 | struct srcimp *srcimp; | ||
1132 | struct ct_mixer *mixer; | ||
1133 | int i = 0; | ||
1134 | |||
1135 | if (NULL == atc) | ||
1136 | return 0; | ||
1137 | |||
1138 | if (atc->timer) { | ||
1139 | ct_timer_free(atc->timer); | ||
1140 | atc->timer = NULL; | ||
1141 | } | ||
1142 | |||
1143 | /* Stop hardware and disable all interrupts */ | ||
1144 | if (NULL != atc->hw) | ||
1145 | ((struct hw *)atc->hw)->card_stop(atc->hw); | ||
1146 | |||
1147 | /* Destroy internal mixer objects */ | ||
1148 | if (NULL != atc->mixer) { | ||
1149 | mixer = atc->mixer; | ||
1150 | mixer->set_input_left(mixer, MIX_LINE_IN, NULL); | ||
1151 | mixer->set_input_right(mixer, MIX_LINE_IN, NULL); | ||
1152 | mixer->set_input_left(mixer, MIX_MIC_IN, NULL); | ||
1153 | mixer->set_input_right(mixer, MIX_MIC_IN, NULL); | ||
1154 | mixer->set_input_left(mixer, MIX_SPDIF_IN, NULL); | ||
1155 | mixer->set_input_right(mixer, MIX_SPDIF_IN, NULL); | ||
1156 | ct_mixer_destroy(atc->mixer); | ||
1157 | } | ||
1158 | |||
1159 | if (NULL != atc->daios) { | ||
1160 | daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; | ||
1161 | for (i = 0; i < atc->n_daio; i++) { | ||
1162 | daio = atc->daios[i]; | ||
1163 | if (daio->type < LINEIM) { | ||
1164 | dao = container_of(daio, struct dao, daio); | ||
1165 | dao->ops->clear_left_input(dao); | ||
1166 | dao->ops->clear_right_input(dao); | ||
1167 | } else { | ||
1168 | dai = container_of(daio, struct dai, daio); | ||
1169 | /* some thing to do for dai ... */ | ||
1170 | } | ||
1171 | daio_mgr->put_daio(daio_mgr, daio); | ||
1172 | } | ||
1173 | kfree(atc->daios); | ||
1174 | } | ||
1175 | |||
1176 | if (NULL != atc->pcm) { | ||
1177 | sum_mgr = atc->rsc_mgrs[SUM]; | ||
1178 | for (i = 0; i < atc->n_pcm; i++) | ||
1179 | sum_mgr->put_sum(sum_mgr, atc->pcm[i]); | ||
1180 | |||
1181 | kfree(atc->pcm); | ||
1182 | } | ||
1183 | |||
1184 | if (NULL != atc->srcs) { | ||
1185 | src_mgr = atc->rsc_mgrs[SRC]; | ||
1186 | for (i = 0; i < atc->n_src; i++) | ||
1187 | src_mgr->put_src(src_mgr, atc->srcs[i]); | ||
1188 | |||
1189 | kfree(atc->srcs); | ||
1190 | } | ||
1191 | |||
1192 | if (NULL != atc->srcimps) { | ||
1193 | srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | ||
1194 | for (i = 0; i < atc->n_srcimp; i++) { | ||
1195 | srcimp = atc->srcimps[i]; | ||
1196 | srcimp->ops->unmap(srcimp); | ||
1197 | srcimp_mgr->put_srcimp(srcimp_mgr, atc->srcimps[i]); | ||
1198 | } | ||
1199 | kfree(atc->srcimps); | ||
1200 | } | ||
1201 | |||
1202 | for (i = 0; i < NUM_RSCTYP; i++) { | ||
1203 | if ((NULL != rsc_mgr_funcs[i].destroy) && | ||
1204 | (NULL != atc->rsc_mgrs[i])) | ||
1205 | rsc_mgr_funcs[i].destroy(atc->rsc_mgrs[i]); | ||
1206 | |||
1207 | } | ||
1208 | |||
1209 | if (NULL != atc->hw) | ||
1210 | destroy_hw_obj((struct hw *)atc->hw); | ||
1211 | |||
1212 | /* Destroy device virtual memory manager object */ | ||
1213 | if (NULL != atc->vm) { | ||
1214 | ct_vm_destroy(atc->vm); | ||
1215 | atc->vm = NULL; | ||
1216 | } | ||
1217 | |||
1218 | kfree(atc); | ||
1219 | |||
1220 | return 0; | ||
1221 | } | ||
1222 | |||
1223 | static int atc_dev_free(struct snd_device *dev) | ||
1224 | { | ||
1225 | struct ct_atc *atc = dev->device_data; | ||
1226 | return ct_atc_destroy(atc); | ||
1227 | } | ||
1228 | |||
1229 | static int __devinit atc_identify_card(struct ct_atc *atc) | ||
1230 | { | ||
1231 | const struct snd_pci_quirk *p; | ||
1232 | const struct snd_pci_quirk *list; | ||
1233 | |||
1234 | switch (atc->chip_type) { | ||
1235 | case ATC20K1: | ||
1236 | atc->chip_name = "20K1"; | ||
1237 | list = subsys_20k1_list; | ||
1238 | break; | ||
1239 | case ATC20K2: | ||
1240 | atc->chip_name = "20K2"; | ||
1241 | list = subsys_20k2_list; | ||
1242 | break; | ||
1243 | default: | ||
1244 | return -ENOENT; | ||
1245 | } | ||
1246 | p = snd_pci_quirk_lookup(atc->pci, list); | ||
1247 | if (!p) | ||
1248 | return -ENOENT; | ||
1249 | atc->model = p->value; | ||
1250 | atc->model_name = ct_subsys_name[atc->model]; | ||
1251 | snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n", | ||
1252 | atc->chip_name, atc->model_name, | ||
1253 | atc->pci->subsystem_vendor, | ||
1254 | atc->pci->subsystem_device); | ||
1255 | return 0; | ||
1256 | } | ||
1257 | |||
1258 | int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc) | ||
1259 | { | ||
1260 | enum CTALSADEVS i; | ||
1261 | int err; | ||
1262 | |||
1263 | alsa_dev_funcs[MIXER].public_name = atc->chip_name; | ||
1264 | |||
1265 | for (i = 0; i < NUM_CTALSADEVS; i++) { | ||
1266 | if (NULL == alsa_dev_funcs[i].create) | ||
1267 | continue; | ||
1268 | |||
1269 | err = alsa_dev_funcs[i].create(atc, i, | ||
1270 | alsa_dev_funcs[i].public_name); | ||
1271 | if (err) { | ||
1272 | printk(KERN_ERR "ctxfi: " | ||
1273 | "Creating alsa device %d failed!\n", i); | ||
1274 | return err; | ||
1275 | } | ||
1276 | } | ||
1277 | |||
1278 | return 0; | ||
1279 | } | ||
1280 | |||
1281 | static int __devinit atc_create_hw_devs(struct ct_atc *atc) | ||
1282 | { | ||
1283 | struct hw *hw; | ||
1284 | struct card_conf info = {0}; | ||
1285 | int i, err; | ||
1286 | |||
1287 | err = create_hw_obj(atc->pci, atc->chip_type, atc->model, &hw); | ||
1288 | if (err) { | ||
1289 | printk(KERN_ERR "Failed to create hw obj!!!\n"); | ||
1290 | return err; | ||
1291 | } | ||
1292 | atc->hw = hw; | ||
1293 | |||
1294 | /* Initialize card hardware. */ | ||
1295 | info.rsr = atc->rsr; | ||
1296 | info.msr = atc->msr; | ||
1297 | info.vm_pgt_phys = atc_get_ptp_phys(atc, 0); | ||
1298 | err = hw->card_init(hw, &info); | ||
1299 | if (err < 0) | ||
1300 | return err; | ||
1301 | |||
1302 | for (i = 0; i < NUM_RSCTYP; i++) { | ||
1303 | if (NULL == rsc_mgr_funcs[i].create) | ||
1304 | continue; | ||
1305 | |||
1306 | err = rsc_mgr_funcs[i].create(atc->hw, &atc->rsc_mgrs[i]); | ||
1307 | if (err) { | ||
1308 | printk(KERN_ERR "ctxfi: " | ||
1309 | "Failed to create rsc_mgr %d!!!\n", i); | ||
1310 | return err; | ||
1311 | } | ||
1312 | } | ||
1313 | |||
1314 | return 0; | ||
1315 | } | ||
1316 | |||
1317 | static int __devinit atc_get_resources(struct ct_atc *atc) | ||
1318 | { | ||
1319 | struct daio_desc da_desc = {0}; | ||
1320 | struct daio_mgr *daio_mgr; | ||
1321 | struct src_desc src_dsc = {0}; | ||
1322 | struct src_mgr *src_mgr; | ||
1323 | struct srcimp_desc srcimp_dsc = {0}; | ||
1324 | struct srcimp_mgr *srcimp_mgr; | ||
1325 | struct sum_desc sum_dsc = {0}; | ||
1326 | struct sum_mgr *sum_mgr; | ||
1327 | int err, i; | ||
1328 | |||
1329 | atc->daios = kzalloc(sizeof(void *)*(DAIONUM), GFP_KERNEL); | ||
1330 | if (NULL == atc->daios) | ||
1331 | return -ENOMEM; | ||
1332 | |||
1333 | atc->srcs = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); | ||
1334 | if (NULL == atc->srcs) | ||
1335 | return -ENOMEM; | ||
1336 | |||
1337 | atc->srcimps = kzalloc(sizeof(void *)*(2*2), GFP_KERNEL); | ||
1338 | if (NULL == atc->srcimps) | ||
1339 | return -ENOMEM; | ||
1340 | |||
1341 | atc->pcm = kzalloc(sizeof(void *)*(2*4), GFP_KERNEL); | ||
1342 | if (NULL == atc->pcm) | ||
1343 | return -ENOMEM; | ||
1344 | |||
1345 | daio_mgr = (struct daio_mgr *)atc->rsc_mgrs[DAIO]; | ||
1346 | da_desc.msr = atc->msr; | ||
1347 | for (i = 0, atc->n_daio = 0; i < DAIONUM-1; i++) { | ||
1348 | da_desc.type = i; | ||
1349 | err = daio_mgr->get_daio(daio_mgr, &da_desc, | ||
1350 | (struct daio **)&atc->daios[i]); | ||
1351 | if (err) { | ||
1352 | printk(KERN_ERR "ctxfi: Failed to get DAIO " | ||
1353 | "resource %d!!!\n", i); | ||
1354 | return err; | ||
1355 | } | ||
1356 | atc->n_daio++; | ||
1357 | } | ||
1358 | if (atc->model == CTSB073X) | ||
1359 | da_desc.type = SPDIFI1; | ||
1360 | else | ||
1361 | da_desc.type = SPDIFIO; | ||
1362 | err = daio_mgr->get_daio(daio_mgr, &da_desc, | ||
1363 | (struct daio **)&atc->daios[i]); | ||
1364 | if (err) { | ||
1365 | printk(KERN_ERR "ctxfi: Failed to get S/PDIF-in resource!!!\n"); | ||
1366 | return err; | ||
1367 | } | ||
1368 | atc->n_daio++; | ||
1369 | |||
1370 | src_mgr = atc->rsc_mgrs[SRC]; | ||
1371 | src_dsc.multi = 1; | ||
1372 | src_dsc.msr = atc->msr; | ||
1373 | src_dsc.mode = ARCRW; | ||
1374 | for (i = 0, atc->n_src = 0; i < (2*2); i++) { | ||
1375 | err = src_mgr->get_src(src_mgr, &src_dsc, | ||
1376 | (struct src **)&atc->srcs[i]); | ||
1377 | if (err) | ||
1378 | return err; | ||
1379 | |||
1380 | atc->n_src++; | ||
1381 | } | ||
1382 | |||
1383 | srcimp_mgr = atc->rsc_mgrs[SRCIMP]; | ||
1384 | srcimp_dsc.msr = 8; /* SRCIMPs for S/PDIFIn SRT */ | ||
1385 | for (i = 0, atc->n_srcimp = 0; i < (2*1); i++) { | ||
1386 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, | ||
1387 | (struct srcimp **)&atc->srcimps[i]); | ||
1388 | if (err) | ||
1389 | return err; | ||
1390 | |||
1391 | atc->n_srcimp++; | ||
1392 | } | ||
1393 | srcimp_dsc.msr = 8; /* SRCIMPs for LINE/MICIn SRT */ | ||
1394 | for (i = 0; i < (2*1); i++) { | ||
1395 | err = srcimp_mgr->get_srcimp(srcimp_mgr, &srcimp_dsc, | ||
1396 | (struct srcimp **)&atc->srcimps[2*1+i]); | ||
1397 | if (err) | ||
1398 | return err; | ||
1399 | |||
1400 | atc->n_srcimp++; | ||
1401 | } | ||
1402 | |||
1403 | sum_mgr = atc->rsc_mgrs[SUM]; | ||
1404 | sum_dsc.msr = atc->msr; | ||
1405 | for (i = 0, atc->n_pcm = 0; i < (2*4); i++) { | ||
1406 | err = sum_mgr->get_sum(sum_mgr, &sum_dsc, | ||
1407 | (struct sum **)&atc->pcm[i]); | ||
1408 | if (err) | ||
1409 | return err; | ||
1410 | |||
1411 | atc->n_pcm++; | ||
1412 | } | ||
1413 | |||
1414 | err = ct_mixer_create(atc, (struct ct_mixer **)&atc->mixer); | ||
1415 | if (err) { | ||
1416 | printk(KERN_ERR "ctxfi: Failed to create mixer obj!!!\n"); | ||
1417 | return err; | ||
1418 | } | ||
1419 | |||
1420 | return 0; | ||
1421 | } | ||
1422 | |||
1423 | static void __devinit | ||
1424 | atc_connect_dai(struct src_mgr *src_mgr, struct dai *dai, | ||
1425 | struct src **srcs, struct srcimp **srcimps) | ||
1426 | { | ||
1427 | struct rsc *rscs[2] = {NULL}; | ||
1428 | struct src *src; | ||
1429 | struct srcimp *srcimp; | ||
1430 | int i = 0; | ||
1431 | |||
1432 | rscs[0] = &dai->daio.rscl; | ||
1433 | rscs[1] = &dai->daio.rscr; | ||
1434 | for (i = 0; i < 2; i++) { | ||
1435 | src = srcs[i]; | ||
1436 | srcimp = srcimps[i]; | ||
1437 | srcimp->ops->map(srcimp, src, rscs[i]); | ||
1438 | src_mgr->src_disable(src_mgr, src); | ||
1439 | } | ||
1440 | |||
1441 | src_mgr->commit_write(src_mgr); /* Actually disable SRCs */ | ||
1442 | |||
1443 | src = srcs[0]; | ||
1444 | src->ops->set_pm(src, 1); | ||
1445 | for (i = 0; i < 2; i++) { | ||
1446 | src = srcs[i]; | ||
1447 | src->ops->set_state(src, SRC_STATE_RUN); | ||
1448 | src->ops->commit_write(src); | ||
1449 | src_mgr->src_enable_s(src_mgr, src); | ||
1450 | } | ||
1451 | |||
1452 | dai->ops->set_srt_srcl(dai, &(srcs[0]->rsc)); | ||
1453 | dai->ops->set_srt_srcr(dai, &(srcs[1]->rsc)); | ||
1454 | |||
1455 | dai->ops->set_enb_src(dai, 1); | ||
1456 | dai->ops->set_enb_srt(dai, 1); | ||
1457 | dai->ops->commit_write(dai); | ||
1458 | |||
1459 | src_mgr->commit_write(src_mgr); /* Synchronously enable SRCs */ | ||
1460 | } | ||
1461 | |||
1462 | static void __devinit atc_connect_resources(struct ct_atc *atc) | ||
1463 | { | ||
1464 | struct dai *dai; | ||
1465 | struct dao *dao; | ||
1466 | struct src *src; | ||
1467 | struct sum *sum; | ||
1468 | struct ct_mixer *mixer; | ||
1469 | struct rsc *rscs[2] = {NULL}; | ||
1470 | int i, j; | ||
1471 | |||
1472 | mixer = atc->mixer; | ||
1473 | |||
1474 | for (i = MIX_WAVE_FRONT, j = LINEO1; i <= MIX_SPDIF_OUT; i++, j++) { | ||
1475 | mixer->get_output_ports(mixer, i, &rscs[0], &rscs[1]); | ||
1476 | dao = container_of(atc->daios[j], struct dao, daio); | ||
1477 | dao->ops->set_left_input(dao, rscs[0]); | ||
1478 | dao->ops->set_right_input(dao, rscs[1]); | ||
1479 | } | ||
1480 | |||
1481 | dai = container_of(atc->daios[LINEIM], struct dai, daio); | ||
1482 | atc_connect_dai(atc->rsc_mgrs[SRC], dai, | ||
1483 | (struct src **)&atc->srcs[2], | ||
1484 | (struct srcimp **)&atc->srcimps[2]); | ||
1485 | src = atc->srcs[2]; | ||
1486 | mixer->set_input_left(mixer, MIX_LINE_IN, &src->rsc); | ||
1487 | src = atc->srcs[3]; | ||
1488 | mixer->set_input_right(mixer, MIX_LINE_IN, &src->rsc); | ||
1489 | |||
1490 | dai = container_of(atc->daios[SPDIFIO], struct dai, daio); | ||
1491 | atc_connect_dai(atc->rsc_mgrs[SRC], dai, | ||
1492 | (struct src **)&atc->srcs[0], | ||
1493 | (struct srcimp **)&atc->srcimps[0]); | ||
1494 | |||
1495 | src = atc->srcs[0]; | ||
1496 | mixer->set_input_left(mixer, MIX_SPDIF_IN, &src->rsc); | ||
1497 | src = atc->srcs[1]; | ||
1498 | mixer->set_input_right(mixer, MIX_SPDIF_IN, &src->rsc); | ||
1499 | |||
1500 | for (i = MIX_PCMI_FRONT, j = 0; i <= MIX_PCMI_SURROUND; i++, j += 2) { | ||
1501 | sum = atc->pcm[j]; | ||
1502 | mixer->set_input_left(mixer, i, &sum->rsc); | ||
1503 | sum = atc->pcm[j+1]; | ||
1504 | mixer->set_input_right(mixer, i, &sum->rsc); | ||
1505 | } | ||
1506 | } | ||
1507 | |||
1508 | static struct ct_atc atc_preset __devinitdata = { | ||
1509 | .map_audio_buffer = ct_map_audio_buffer, | ||
1510 | .unmap_audio_buffer = ct_unmap_audio_buffer, | ||
1511 | .pcm_playback_prepare = atc_pcm_playback_prepare, | ||
1512 | .pcm_release_resources = atc_pcm_release_resources, | ||
1513 | .pcm_playback_start = atc_pcm_playback_start, | ||
1514 | .pcm_playback_stop = atc_pcm_stop, | ||
1515 | .pcm_playback_position = atc_pcm_playback_position, | ||
1516 | .pcm_capture_prepare = atc_pcm_capture_prepare, | ||
1517 | .pcm_capture_start = atc_pcm_capture_start, | ||
1518 | .pcm_capture_stop = atc_pcm_stop, | ||
1519 | .pcm_capture_position = atc_pcm_capture_position, | ||
1520 | .spdif_passthru_playback_prepare = spdif_passthru_playback_prepare, | ||
1521 | .get_ptp_phys = atc_get_ptp_phys, | ||
1522 | .select_line_in = atc_select_line_in, | ||
1523 | .select_mic_in = atc_select_mic_in, | ||
1524 | .select_digit_io = atc_select_digit_io, | ||
1525 | .line_front_unmute = atc_line_front_unmute, | ||
1526 | .line_surround_unmute = atc_line_surround_unmute, | ||
1527 | .line_clfe_unmute = atc_line_clfe_unmute, | ||
1528 | .line_rear_unmute = atc_line_rear_unmute, | ||
1529 | .line_in_unmute = atc_line_in_unmute, | ||
1530 | .spdif_out_unmute = atc_spdif_out_unmute, | ||
1531 | .spdif_in_unmute = atc_spdif_in_unmute, | ||
1532 | .spdif_out_get_status = atc_spdif_out_get_status, | ||
1533 | .spdif_out_set_status = atc_spdif_out_set_status, | ||
1534 | .spdif_out_passthru = atc_spdif_out_passthru, | ||
1535 | .have_digit_io_switch = atc_have_digit_io_switch, | ||
1536 | }; | ||
1537 | |||
1538 | /** | ||
1539 | * ct_atc_create - create and initialize a hardware manager | ||
1540 | * @card: corresponding alsa card object | ||
1541 | * @pci: corresponding kernel pci device object | ||
1542 | * @ratc: return created object address in it | ||
1543 | * | ||
1544 | * Creates and initializes a hardware manager. | ||
1545 | * | ||
1546 | * Creates kmallocated ct_atc structure. Initializes hardware. | ||
1547 | * Returns 0 if suceeds, or negative error code if fails. | ||
1548 | */ | ||
1549 | |||
1550 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | ||
1551 | unsigned int rsr, unsigned int msr, | ||
1552 | int chip_type, struct ct_atc **ratc) | ||
1553 | { | ||
1554 | struct ct_atc *atc; | ||
1555 | static struct snd_device_ops ops = { | ||
1556 | .dev_free = atc_dev_free, | ||
1557 | }; | ||
1558 | int err; | ||
1559 | |||
1560 | *ratc = NULL; | ||
1561 | |||
1562 | atc = kzalloc(sizeof(*atc), GFP_KERNEL); | ||
1563 | if (NULL == atc) | ||
1564 | return -ENOMEM; | ||
1565 | |||
1566 | /* Set operations */ | ||
1567 | *atc = atc_preset; | ||
1568 | |||
1569 | atc->card = card; | ||
1570 | atc->pci = pci; | ||
1571 | atc->rsr = rsr; | ||
1572 | atc->msr = msr; | ||
1573 | atc->chip_type = chip_type; | ||
1574 | |||
1575 | spin_lock_init(&atc->atc_lock); | ||
1576 | |||
1577 | /* Find card model */ | ||
1578 | err = atc_identify_card(atc); | ||
1579 | if (err < 0) { | ||
1580 | printk(KERN_ERR "ctatc: Card not recognised\n"); | ||
1581 | goto error1; | ||
1582 | } | ||
1583 | |||
1584 | /* Set up device virtual memory management object */ | ||
1585 | err = ct_vm_create(&atc->vm); | ||
1586 | if (err < 0) | ||
1587 | goto error1; | ||
1588 | |||
1589 | /* Create all atc hw devices */ | ||
1590 | err = atc_create_hw_devs(atc); | ||
1591 | if (err < 0) | ||
1592 | goto error1; | ||
1593 | |||
1594 | /* Get resources */ | ||
1595 | err = atc_get_resources(atc); | ||
1596 | if (err < 0) | ||
1597 | goto error1; | ||
1598 | |||
1599 | /* Build topology */ | ||
1600 | atc_connect_resources(atc); | ||
1601 | |||
1602 | atc->timer = ct_timer_new(atc); | ||
1603 | if (!atc->timer) | ||
1604 | goto error1; | ||
1605 | |||
1606 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, atc, &ops); | ||
1607 | if (err < 0) | ||
1608 | goto error1; | ||
1609 | |||
1610 | snd_card_set_dev(card, &pci->dev); | ||
1611 | |||
1612 | *ratc = atc; | ||
1613 | return 0; | ||
1614 | |||
1615 | error1: | ||
1616 | ct_atc_destroy(atc); | ||
1617 | printk(KERN_ERR "ctxfi: Something wrong!!!\n"); | ||
1618 | return err; | ||
1619 | } | ||
diff --git a/sound/pci/ctxfi/ctatc.h b/sound/pci/ctxfi/ctatc.h new file mode 100644 index 000000000000..a03347232e84 --- /dev/null +++ b/sound/pci/ctxfi/ctatc.h | |||
@@ -0,0 +1,147 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctatc.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of the device resource management object. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date Mar 28 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef CTATC_H | ||
19 | #define CTATC_H | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/spinlock_types.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/timer.h> | ||
25 | #include <sound/core.h> | ||
26 | |||
27 | #include "ctvmem.h" | ||
28 | #include "ctresource.h" | ||
29 | |||
30 | enum CTALSADEVS { /* Types of alsa devices */ | ||
31 | FRONT, | ||
32 | SURROUND, | ||
33 | CLFE, | ||
34 | SIDE, | ||
35 | IEC958, | ||
36 | MIXER, | ||
37 | NUM_CTALSADEVS /* This should always be the last */ | ||
38 | }; | ||
39 | |||
40 | struct ct_atc_chip_sub_details { | ||
41 | u16 subsys; | ||
42 | const char *nm_model; | ||
43 | }; | ||
44 | |||
45 | struct ct_atc_chip_details { | ||
46 | u16 vendor; | ||
47 | u16 device; | ||
48 | const struct ct_atc_chip_sub_details *sub_details; | ||
49 | const char *nm_card; | ||
50 | }; | ||
51 | |||
52 | struct ct_atc; | ||
53 | struct ct_timer; | ||
54 | struct ct_timer_instance; | ||
55 | |||
56 | /* alsa pcm stream descriptor */ | ||
57 | struct ct_atc_pcm { | ||
58 | struct snd_pcm_substream *substream; | ||
59 | void (*interrupt)(struct ct_atc_pcm *apcm); | ||
60 | struct ct_timer_instance *timer; | ||
61 | unsigned int started:1; | ||
62 | |||
63 | /* Only mono and interleaved modes are supported now. */ | ||
64 | struct ct_vm_block *vm_block; | ||
65 | void *src; /* SRC for interacting with host memory */ | ||
66 | void **srccs; /* SRCs for sample rate conversion */ | ||
67 | void **srcimps; /* SRC Input Mappers */ | ||
68 | void **amixers; /* AMIXERs for routing converted data */ | ||
69 | void *mono; /* A SUM resource for mixing chs to one */ | ||
70 | unsigned char n_srcc; /* Number of converting SRCs */ | ||
71 | unsigned char n_srcimp; /* Number of SRC Input Mappers */ | ||
72 | unsigned char n_amixer; /* Number of AMIXERs */ | ||
73 | }; | ||
74 | |||
75 | /* Chip resource management object */ | ||
76 | struct ct_atc { | ||
77 | struct pci_dev *pci; | ||
78 | struct snd_card *card; | ||
79 | unsigned int rsr; /* reference sample rate in Hz */ | ||
80 | unsigned int msr; /* master sample rate in rsr */ | ||
81 | unsigned int pll_rate; /* current rate of Phase Lock Loop */ | ||
82 | |||
83 | int chip_type; | ||
84 | int model; | ||
85 | const char *chip_name; | ||
86 | const char *model_name; | ||
87 | |||
88 | struct ct_vm *vm; /* device virtual memory manager for this card */ | ||
89 | int (*map_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
90 | void (*unmap_audio_buffer)(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
91 | unsigned long (*get_ptp_phys)(struct ct_atc *atc, int index); | ||
92 | |||
93 | spinlock_t atc_lock; | ||
94 | |||
95 | int (*pcm_playback_prepare)(struct ct_atc *atc, | ||
96 | struct ct_atc_pcm *apcm); | ||
97 | int (*pcm_playback_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
98 | int (*pcm_playback_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
99 | int (*pcm_playback_position)(struct ct_atc *atc, | ||
100 | struct ct_atc_pcm *apcm); | ||
101 | int (*spdif_passthru_playback_prepare)(struct ct_atc *atc, | ||
102 | struct ct_atc_pcm *apcm); | ||
103 | int (*pcm_capture_prepare)(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
104 | int (*pcm_capture_start)(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
105 | int (*pcm_capture_stop)(struct ct_atc *atc, struct ct_atc_pcm *apcm); | ||
106 | int (*pcm_capture_position)(struct ct_atc *atc, | ||
107 | struct ct_atc_pcm *apcm); | ||
108 | int (*pcm_release_resources)(struct ct_atc *atc, | ||
109 | struct ct_atc_pcm *apcm); | ||
110 | int (*select_line_in)(struct ct_atc *atc); | ||
111 | int (*select_mic_in)(struct ct_atc *atc); | ||
112 | int (*select_digit_io)(struct ct_atc *atc); | ||
113 | int (*line_front_unmute)(struct ct_atc *atc, unsigned char state); | ||
114 | int (*line_surround_unmute)(struct ct_atc *atc, unsigned char state); | ||
115 | int (*line_clfe_unmute)(struct ct_atc *atc, unsigned char state); | ||
116 | int (*line_rear_unmute)(struct ct_atc *atc, unsigned char state); | ||
117 | int (*line_in_unmute)(struct ct_atc *atc, unsigned char state); | ||
118 | int (*spdif_out_unmute)(struct ct_atc *atc, unsigned char state); | ||
119 | int (*spdif_in_unmute)(struct ct_atc *atc, unsigned char state); | ||
120 | int (*spdif_out_get_status)(struct ct_atc *atc, unsigned int *status); | ||
121 | int (*spdif_out_set_status)(struct ct_atc *atc, unsigned int status); | ||
122 | int (*spdif_out_passthru)(struct ct_atc *atc, unsigned char state); | ||
123 | int (*have_digit_io_switch)(struct ct_atc *atc); | ||
124 | |||
125 | /* Don't touch! Used for internal object. */ | ||
126 | void *rsc_mgrs[NUM_RSCTYP]; /* chip resource managers */ | ||
127 | void *mixer; /* internal mixer object */ | ||
128 | void *hw; /* chip specific hardware access object */ | ||
129 | void **daios; /* digital audio io resources */ | ||
130 | void **pcm; /* SUMs for collecting all pcm stream */ | ||
131 | void **srcs; /* Sample Rate Converters for input signal */ | ||
132 | void **srcimps; /* input mappers for SRCs */ | ||
133 | unsigned char n_daio; | ||
134 | unsigned char n_src; | ||
135 | unsigned char n_srcimp; | ||
136 | unsigned char n_pcm; | ||
137 | |||
138 | struct ct_timer *timer; | ||
139 | }; | ||
140 | |||
141 | |||
142 | int __devinit ct_atc_create(struct snd_card *card, struct pci_dev *pci, | ||
143 | unsigned int rsr, unsigned int msr, int chip_type, | ||
144 | struct ct_atc **ratc); | ||
145 | int __devinit ct_atc_create_alsa_devs(struct ct_atc *atc); | ||
146 | |||
147 | #endif /* CTATC_H */ | ||
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c new file mode 100644 index 000000000000..082e35c08c02 --- /dev/null +++ b/sound/pci/ctxfi/ctdaio.c | |||
@@ -0,0 +1,769 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctdaio.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of Digital Audio Input Output | ||
12 | * resource management object. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 23 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "ctdaio.h" | ||
20 | #include "cthardware.h" | ||
21 | #include "ctimap.h" | ||
22 | #include <linux/slab.h> | ||
23 | #include <linux/kernel.h> | ||
24 | |||
25 | #define DAIO_RESOURCE_NUM NUM_DAIOTYP | ||
26 | #define DAIO_OUT_MAX SPDIFOO | ||
27 | |||
28 | union daio_usage { | ||
29 | struct { | ||
30 | unsigned short lineo1:1; | ||
31 | unsigned short lineo2:1; | ||
32 | unsigned short lineo3:1; | ||
33 | unsigned short lineo4:1; | ||
34 | unsigned short spdifoo:1; | ||
35 | unsigned short lineim:1; | ||
36 | unsigned short spdifio:1; | ||
37 | unsigned short spdifi1:1; | ||
38 | } bf; | ||
39 | unsigned short data; | ||
40 | }; | ||
41 | |||
42 | struct daio_rsc_idx { | ||
43 | unsigned short left; | ||
44 | unsigned short right; | ||
45 | }; | ||
46 | |||
47 | struct daio_rsc_idx idx_20k1[NUM_DAIOTYP] = { | ||
48 | [LINEO1] = {.left = 0x00, .right = 0x01}, | ||
49 | [LINEO2] = {.left = 0x18, .right = 0x19}, | ||
50 | [LINEO3] = {.left = 0x08, .right = 0x09}, | ||
51 | [LINEO4] = {.left = 0x10, .right = 0x11}, | ||
52 | [LINEIM] = {.left = 0x1b5, .right = 0x1bd}, | ||
53 | [SPDIFOO] = {.left = 0x20, .right = 0x21}, | ||
54 | [SPDIFIO] = {.left = 0x15, .right = 0x1d}, | ||
55 | [SPDIFI1] = {.left = 0x95, .right = 0x9d}, | ||
56 | }; | ||
57 | |||
58 | struct daio_rsc_idx idx_20k2[NUM_DAIOTYP] = { | ||
59 | [LINEO1] = {.left = 0x40, .right = 0x41}, | ||
60 | [LINEO2] = {.left = 0x70, .right = 0x71}, | ||
61 | [LINEO3] = {.left = 0x50, .right = 0x51}, | ||
62 | [LINEO4] = {.left = 0x60, .right = 0x61}, | ||
63 | [LINEIM] = {.left = 0x45, .right = 0xc5}, | ||
64 | [SPDIFOO] = {.left = 0x00, .right = 0x01}, | ||
65 | [SPDIFIO] = {.left = 0x05, .right = 0x85}, | ||
66 | }; | ||
67 | |||
68 | static int daio_master(struct rsc *rsc) | ||
69 | { | ||
70 | /* Actually, this is not the resource index of DAIO. | ||
71 | * For DAO, it is the input mapper index. And, for DAI, | ||
72 | * it is the output time-slot index. */ | ||
73 | return rsc->conj = rsc->idx; | ||
74 | } | ||
75 | |||
76 | static int daio_index(const struct rsc *rsc) | ||
77 | { | ||
78 | return rsc->conj; | ||
79 | } | ||
80 | |||
81 | static int daio_out_next_conj(struct rsc *rsc) | ||
82 | { | ||
83 | return rsc->conj += 2; | ||
84 | } | ||
85 | |||
86 | static int daio_in_next_conj_20k1(struct rsc *rsc) | ||
87 | { | ||
88 | return rsc->conj += 0x200; | ||
89 | } | ||
90 | |||
91 | static int daio_in_next_conj_20k2(struct rsc *rsc) | ||
92 | { | ||
93 | return rsc->conj += 0x100; | ||
94 | } | ||
95 | |||
96 | static struct rsc_ops daio_out_rsc_ops = { | ||
97 | .master = daio_master, | ||
98 | .next_conj = daio_out_next_conj, | ||
99 | .index = daio_index, | ||
100 | .output_slot = NULL, | ||
101 | }; | ||
102 | |||
103 | static struct rsc_ops daio_in_rsc_ops_20k1 = { | ||
104 | .master = daio_master, | ||
105 | .next_conj = daio_in_next_conj_20k1, | ||
106 | .index = NULL, | ||
107 | .output_slot = daio_index, | ||
108 | }; | ||
109 | |||
110 | static struct rsc_ops daio_in_rsc_ops_20k2 = { | ||
111 | .master = daio_master, | ||
112 | .next_conj = daio_in_next_conj_20k2, | ||
113 | .index = NULL, | ||
114 | .output_slot = daio_index, | ||
115 | }; | ||
116 | |||
117 | static unsigned int daio_device_index(enum DAIOTYP type, struct hw *hw) | ||
118 | { | ||
119 | switch (hw->chip_type) { | ||
120 | case ATC20K1: | ||
121 | switch (type) { | ||
122 | case SPDIFOO: return 0; | ||
123 | case SPDIFIO: return 0; | ||
124 | case SPDIFI1: return 1; | ||
125 | case LINEO1: return 4; | ||
126 | case LINEO2: return 7; | ||
127 | case LINEO3: return 5; | ||
128 | case LINEO4: return 6; | ||
129 | case LINEIM: return 7; | ||
130 | default: return -EINVAL; | ||
131 | } | ||
132 | case ATC20K2: | ||
133 | switch (type) { | ||
134 | case SPDIFOO: return 0; | ||
135 | case SPDIFIO: return 0; | ||
136 | case LINEO1: return 4; | ||
137 | case LINEO2: return 7; | ||
138 | case LINEO3: return 5; | ||
139 | case LINEO4: return 6; | ||
140 | case LINEIM: return 4; | ||
141 | default: return -EINVAL; | ||
142 | } | ||
143 | default: | ||
144 | return -EINVAL; | ||
145 | } | ||
146 | } | ||
147 | |||
148 | static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc); | ||
149 | |||
150 | static int dao_spdif_get_spos(struct dao *dao, unsigned int *spos) | ||
151 | { | ||
152 | ((struct hw *)dao->hw)->dao_get_spos(dao->ctrl_blk, spos); | ||
153 | return 0; | ||
154 | } | ||
155 | |||
156 | static int dao_spdif_set_spos(struct dao *dao, unsigned int spos) | ||
157 | { | ||
158 | ((struct hw *)dao->hw)->dao_set_spos(dao->ctrl_blk, spos); | ||
159 | return 0; | ||
160 | } | ||
161 | |||
162 | static int dao_commit_write(struct dao *dao) | ||
163 | { | ||
164 | ((struct hw *)dao->hw)->dao_commit_write(dao->hw, | ||
165 | daio_device_index(dao->daio.type, dao->hw), dao->ctrl_blk); | ||
166 | return 0; | ||
167 | } | ||
168 | |||
169 | static int dao_set_left_input(struct dao *dao, struct rsc *input) | ||
170 | { | ||
171 | struct imapper *entry; | ||
172 | struct daio *daio = &dao->daio; | ||
173 | int i; | ||
174 | |||
175 | entry = kzalloc((sizeof(*entry) * daio->rscl.msr), GFP_KERNEL); | ||
176 | if (NULL == entry) | ||
177 | return -ENOMEM; | ||
178 | |||
179 | /* Program master and conjugate resources */ | ||
180 | input->ops->master(input); | ||
181 | daio->rscl.ops->master(&daio->rscl); | ||
182 | for (i = 0; i < daio->rscl.msr; i++, entry++) { | ||
183 | entry->slot = input->ops->output_slot(input); | ||
184 | entry->user = entry->addr = daio->rscl.ops->index(&daio->rscl); | ||
185 | dao->mgr->imap_add(dao->mgr, entry); | ||
186 | dao->imappers[i] = entry; | ||
187 | |||
188 | input->ops->next_conj(input); | ||
189 | daio->rscl.ops->next_conj(&daio->rscl); | ||
190 | } | ||
191 | input->ops->master(input); | ||
192 | daio->rscl.ops->master(&daio->rscl); | ||
193 | |||
194 | return 0; | ||
195 | } | ||
196 | |||
197 | static int dao_set_right_input(struct dao *dao, struct rsc *input) | ||
198 | { | ||
199 | struct imapper *entry; | ||
200 | struct daio *daio = &dao->daio; | ||
201 | int i; | ||
202 | |||
203 | entry = kzalloc((sizeof(*entry) * daio->rscr.msr), GFP_KERNEL); | ||
204 | if (NULL == entry) | ||
205 | return -ENOMEM; | ||
206 | |||
207 | /* Program master and conjugate resources */ | ||
208 | input->ops->master(input); | ||
209 | daio->rscr.ops->master(&daio->rscr); | ||
210 | for (i = 0; i < daio->rscr.msr; i++, entry++) { | ||
211 | entry->slot = input->ops->output_slot(input); | ||
212 | entry->user = entry->addr = daio->rscr.ops->index(&daio->rscr); | ||
213 | dao->mgr->imap_add(dao->mgr, entry); | ||
214 | dao->imappers[daio->rscl.msr + i] = entry; | ||
215 | |||
216 | input->ops->next_conj(input); | ||
217 | daio->rscr.ops->next_conj(&daio->rscr); | ||
218 | } | ||
219 | input->ops->master(input); | ||
220 | daio->rscr.ops->master(&daio->rscr); | ||
221 | |||
222 | return 0; | ||
223 | } | ||
224 | |||
225 | static int dao_clear_left_input(struct dao *dao) | ||
226 | { | ||
227 | struct imapper *entry; | ||
228 | struct daio *daio = &dao->daio; | ||
229 | int i; | ||
230 | |||
231 | if (NULL == dao->imappers[0]) | ||
232 | return 0; | ||
233 | |||
234 | entry = dao->imappers[0]; | ||
235 | dao->mgr->imap_delete(dao->mgr, entry); | ||
236 | /* Program conjugate resources */ | ||
237 | for (i = 1; i < daio->rscl.msr; i++) { | ||
238 | entry = dao->imappers[i]; | ||
239 | dao->mgr->imap_delete(dao->mgr, entry); | ||
240 | dao->imappers[i] = NULL; | ||
241 | } | ||
242 | |||
243 | kfree(dao->imappers[0]); | ||
244 | dao->imappers[0] = NULL; | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int dao_clear_right_input(struct dao *dao) | ||
250 | { | ||
251 | struct imapper *entry; | ||
252 | struct daio *daio = &dao->daio; | ||
253 | int i; | ||
254 | |||
255 | if (NULL == dao->imappers[daio->rscl.msr]) | ||
256 | return 0; | ||
257 | |||
258 | entry = dao->imappers[daio->rscl.msr]; | ||
259 | dao->mgr->imap_delete(dao->mgr, entry); | ||
260 | /* Program conjugate resources */ | ||
261 | for (i = 1; i < daio->rscr.msr; i++) { | ||
262 | entry = dao->imappers[daio->rscl.msr + i]; | ||
263 | dao->mgr->imap_delete(dao->mgr, entry); | ||
264 | dao->imappers[daio->rscl.msr + i] = NULL; | ||
265 | } | ||
266 | |||
267 | kfree(dao->imappers[daio->rscl.msr]); | ||
268 | dao->imappers[daio->rscl.msr] = NULL; | ||
269 | |||
270 | return 0; | ||
271 | } | ||
272 | |||
273 | static struct dao_rsc_ops dao_ops = { | ||
274 | .set_spos = dao_spdif_set_spos, | ||
275 | .commit_write = dao_commit_write, | ||
276 | .get_spos = dao_spdif_get_spos, | ||
277 | .reinit = dao_rsc_reinit, | ||
278 | .set_left_input = dao_set_left_input, | ||
279 | .set_right_input = dao_set_right_input, | ||
280 | .clear_left_input = dao_clear_left_input, | ||
281 | .clear_right_input = dao_clear_right_input, | ||
282 | }; | ||
283 | |||
284 | static int dai_set_srt_srcl(struct dai *dai, struct rsc *src) | ||
285 | { | ||
286 | src->ops->master(src); | ||
287 | ((struct hw *)dai->hw)->dai_srt_set_srcm(dai->ctrl_blk, | ||
288 | src->ops->index(src)); | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int dai_set_srt_srcr(struct dai *dai, struct rsc *src) | ||
293 | { | ||
294 | src->ops->master(src); | ||
295 | ((struct hw *)dai->hw)->dai_srt_set_srco(dai->ctrl_blk, | ||
296 | src->ops->index(src)); | ||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | static int dai_set_srt_msr(struct dai *dai, unsigned int msr) | ||
301 | { | ||
302 | unsigned int rsr; | ||
303 | |||
304 | for (rsr = 0; msr > 1; msr >>= 1) | ||
305 | rsr++; | ||
306 | |||
307 | ((struct hw *)dai->hw)->dai_srt_set_rsr(dai->ctrl_blk, rsr); | ||
308 | return 0; | ||
309 | } | ||
310 | |||
311 | static int dai_set_enb_src(struct dai *dai, unsigned int enb) | ||
312 | { | ||
313 | ((struct hw *)dai->hw)->dai_srt_set_ec(dai->ctrl_blk, enb); | ||
314 | return 0; | ||
315 | } | ||
316 | |||
317 | static int dai_set_enb_srt(struct dai *dai, unsigned int enb) | ||
318 | { | ||
319 | ((struct hw *)dai->hw)->dai_srt_set_et(dai->ctrl_blk, enb); | ||
320 | return 0; | ||
321 | } | ||
322 | |||
323 | static int dai_commit_write(struct dai *dai) | ||
324 | { | ||
325 | ((struct hw *)dai->hw)->dai_commit_write(dai->hw, | ||
326 | daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk); | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static struct dai_rsc_ops dai_ops = { | ||
331 | .set_srt_srcl = dai_set_srt_srcl, | ||
332 | .set_srt_srcr = dai_set_srt_srcr, | ||
333 | .set_srt_msr = dai_set_srt_msr, | ||
334 | .set_enb_src = dai_set_enb_src, | ||
335 | .set_enb_srt = dai_set_enb_srt, | ||
336 | .commit_write = dai_commit_write, | ||
337 | }; | ||
338 | |||
339 | static int daio_rsc_init(struct daio *daio, | ||
340 | const struct daio_desc *desc, | ||
341 | void *hw) | ||
342 | { | ||
343 | int err; | ||
344 | unsigned int idx_l, idx_r; | ||
345 | |||
346 | switch (((struct hw *)hw)->chip_type) { | ||
347 | case ATC20K1: | ||
348 | idx_l = idx_20k1[desc->type].left; | ||
349 | idx_r = idx_20k1[desc->type].right; | ||
350 | break; | ||
351 | case ATC20K2: | ||
352 | idx_l = idx_20k2[desc->type].left; | ||
353 | idx_r = idx_20k2[desc->type].right; | ||
354 | break; | ||
355 | default: | ||
356 | return -EINVAL; | ||
357 | } | ||
358 | err = rsc_init(&daio->rscl, idx_l, DAIO, desc->msr, hw); | ||
359 | if (err) | ||
360 | return err; | ||
361 | |||
362 | err = rsc_init(&daio->rscr, idx_r, DAIO, desc->msr, hw); | ||
363 | if (err) | ||
364 | goto error1; | ||
365 | |||
366 | /* Set daio->rscl/r->ops to daio specific ones */ | ||
367 | if (desc->type <= DAIO_OUT_MAX) { | ||
368 | daio->rscl.ops = daio->rscr.ops = &daio_out_rsc_ops; | ||
369 | } else { | ||
370 | switch (((struct hw *)hw)->chip_type) { | ||
371 | case ATC20K1: | ||
372 | daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k1; | ||
373 | break; | ||
374 | case ATC20K2: | ||
375 | daio->rscl.ops = daio->rscr.ops = &daio_in_rsc_ops_20k2; | ||
376 | break; | ||
377 | default: | ||
378 | break; | ||
379 | } | ||
380 | } | ||
381 | daio->type = desc->type; | ||
382 | |||
383 | return 0; | ||
384 | |||
385 | error1: | ||
386 | rsc_uninit(&daio->rscl); | ||
387 | return err; | ||
388 | } | ||
389 | |||
390 | static int daio_rsc_uninit(struct daio *daio) | ||
391 | { | ||
392 | rsc_uninit(&daio->rscl); | ||
393 | rsc_uninit(&daio->rscr); | ||
394 | |||
395 | return 0; | ||
396 | } | ||
397 | |||
398 | static int dao_rsc_init(struct dao *dao, | ||
399 | const struct daio_desc *desc, | ||
400 | struct daio_mgr *mgr) | ||
401 | { | ||
402 | struct hw *hw = mgr->mgr.hw; | ||
403 | unsigned int conf; | ||
404 | int err; | ||
405 | |||
406 | err = daio_rsc_init(&dao->daio, desc, mgr->mgr.hw); | ||
407 | if (err) | ||
408 | return err; | ||
409 | |||
410 | dao->imappers = kzalloc(sizeof(void *)*desc->msr*2, GFP_KERNEL); | ||
411 | if (NULL == dao->imappers) { | ||
412 | err = -ENOMEM; | ||
413 | goto error1; | ||
414 | } | ||
415 | dao->ops = &dao_ops; | ||
416 | dao->mgr = mgr; | ||
417 | dao->hw = hw; | ||
418 | err = hw->dao_get_ctrl_blk(&dao->ctrl_blk); | ||
419 | if (err) | ||
420 | goto error2; | ||
421 | |||
422 | hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk, | ||
423 | daio_device_index(dao->daio.type, hw)); | ||
424 | hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); | ||
425 | |||
426 | conf = (desc->msr & 0x7) | (desc->passthru << 3); | ||
427 | hw->daio_mgr_dao_init(mgr->mgr.ctrl_blk, | ||
428 | daio_device_index(dao->daio.type, hw), conf); | ||
429 | hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk, | ||
430 | daio_device_index(dao->daio.type, hw)); | ||
431 | hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); | ||
432 | |||
433 | return 0; | ||
434 | |||
435 | error2: | ||
436 | kfree(dao->imappers); | ||
437 | dao->imappers = NULL; | ||
438 | error1: | ||
439 | daio_rsc_uninit(&dao->daio); | ||
440 | return err; | ||
441 | } | ||
442 | |||
443 | static int dao_rsc_uninit(struct dao *dao) | ||
444 | { | ||
445 | if (NULL != dao->imappers) { | ||
446 | if (NULL != dao->imappers[0]) | ||
447 | dao_clear_left_input(dao); | ||
448 | |||
449 | if (NULL != dao->imappers[dao->daio.rscl.msr]) | ||
450 | dao_clear_right_input(dao); | ||
451 | |||
452 | kfree(dao->imappers); | ||
453 | dao->imappers = NULL; | ||
454 | } | ||
455 | ((struct hw *)dao->hw)->dao_put_ctrl_blk(dao->ctrl_blk); | ||
456 | dao->hw = dao->ctrl_blk = NULL; | ||
457 | daio_rsc_uninit(&dao->daio); | ||
458 | |||
459 | return 0; | ||
460 | } | ||
461 | |||
462 | static int dao_rsc_reinit(struct dao *dao, const struct dao_desc *desc) | ||
463 | { | ||
464 | struct daio_mgr *mgr = dao->mgr; | ||
465 | struct daio_desc dsc = {0}; | ||
466 | |||
467 | dsc.type = dao->daio.type; | ||
468 | dsc.msr = desc->msr; | ||
469 | dsc.passthru = desc->passthru; | ||
470 | dao_rsc_uninit(dao); | ||
471 | return dao_rsc_init(dao, &dsc, mgr); | ||
472 | } | ||
473 | |||
474 | static int dai_rsc_init(struct dai *dai, | ||
475 | const struct daio_desc *desc, | ||
476 | struct daio_mgr *mgr) | ||
477 | { | ||
478 | int err; | ||
479 | struct hw *hw = mgr->mgr.hw; | ||
480 | unsigned int rsr, msr; | ||
481 | |||
482 | err = daio_rsc_init(&dai->daio, desc, mgr->mgr.hw); | ||
483 | if (err) | ||
484 | return err; | ||
485 | |||
486 | dai->ops = &dai_ops; | ||
487 | dai->hw = mgr->mgr.hw; | ||
488 | err = hw->dai_get_ctrl_blk(&dai->ctrl_blk); | ||
489 | if (err) | ||
490 | goto error1; | ||
491 | |||
492 | for (rsr = 0, msr = desc->msr; msr > 1; msr >>= 1) | ||
493 | rsr++; | ||
494 | |||
495 | hw->dai_srt_set_rsr(dai->ctrl_blk, rsr); | ||
496 | hw->dai_srt_set_drat(dai->ctrl_blk, 0); | ||
497 | /* default to disabling control of a SRC */ | ||
498 | hw->dai_srt_set_ec(dai->ctrl_blk, 0); | ||
499 | hw->dai_srt_set_et(dai->ctrl_blk, 0); /* default to disabling SRT */ | ||
500 | hw->dai_commit_write(hw, | ||
501 | daio_device_index(dai->daio.type, dai->hw), dai->ctrl_blk); | ||
502 | |||
503 | return 0; | ||
504 | |||
505 | error1: | ||
506 | daio_rsc_uninit(&dai->daio); | ||
507 | return err; | ||
508 | } | ||
509 | |||
510 | static int dai_rsc_uninit(struct dai *dai) | ||
511 | { | ||
512 | ((struct hw *)dai->hw)->dai_put_ctrl_blk(dai->ctrl_blk); | ||
513 | dai->hw = dai->ctrl_blk = NULL; | ||
514 | daio_rsc_uninit(&dai->daio); | ||
515 | return 0; | ||
516 | } | ||
517 | |||
518 | static int daio_mgr_get_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) | ||
519 | { | ||
520 | if (((union daio_usage *)mgr->rscs)->data & (0x1 << type)) | ||
521 | return -ENOENT; | ||
522 | |||
523 | ((union daio_usage *)mgr->rscs)->data |= (0x1 << type); | ||
524 | |||
525 | return 0; | ||
526 | } | ||
527 | |||
528 | static int daio_mgr_put_rsc(struct rsc_mgr *mgr, enum DAIOTYP type) | ||
529 | { | ||
530 | ((union daio_usage *)mgr->rscs)->data &= ~(0x1 << type); | ||
531 | |||
532 | return 0; | ||
533 | } | ||
534 | |||
535 | static int get_daio_rsc(struct daio_mgr *mgr, | ||
536 | const struct daio_desc *desc, | ||
537 | struct daio **rdaio) | ||
538 | { | ||
539 | int err; | ||
540 | struct dai *dai = NULL; | ||
541 | struct dao *dao = NULL; | ||
542 | unsigned long flags; | ||
543 | |||
544 | *rdaio = NULL; | ||
545 | |||
546 | /* Check whether there are sufficient daio resources to meet request. */ | ||
547 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
548 | err = daio_mgr_get_rsc(&mgr->mgr, desc->type); | ||
549 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
550 | if (err) { | ||
551 | printk(KERN_ERR "Can't meet DAIO resource request!\n"); | ||
552 | return err; | ||
553 | } | ||
554 | |||
555 | /* Allocate mem for daio resource */ | ||
556 | if (desc->type <= DAIO_OUT_MAX) { | ||
557 | dao = kzalloc(sizeof(*dao), GFP_KERNEL); | ||
558 | if (NULL == dao) { | ||
559 | err = -ENOMEM; | ||
560 | goto error; | ||
561 | } | ||
562 | err = dao_rsc_init(dao, desc, mgr); | ||
563 | if (err) | ||
564 | goto error; | ||
565 | |||
566 | *rdaio = &dao->daio; | ||
567 | } else { | ||
568 | dai = kzalloc(sizeof(*dai), GFP_KERNEL); | ||
569 | if (NULL == dai) { | ||
570 | err = -ENOMEM; | ||
571 | goto error; | ||
572 | } | ||
573 | err = dai_rsc_init(dai, desc, mgr); | ||
574 | if (err) | ||
575 | goto error; | ||
576 | |||
577 | *rdaio = &dai->daio; | ||
578 | } | ||
579 | |||
580 | mgr->daio_enable(mgr, *rdaio); | ||
581 | mgr->commit_write(mgr); | ||
582 | |||
583 | return 0; | ||
584 | |||
585 | error: | ||
586 | if (NULL != dao) | ||
587 | kfree(dao); | ||
588 | else if (NULL != dai) | ||
589 | kfree(dai); | ||
590 | |||
591 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
592 | daio_mgr_put_rsc(&mgr->mgr, desc->type); | ||
593 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
594 | return err; | ||
595 | } | ||
596 | |||
597 | static int put_daio_rsc(struct daio_mgr *mgr, struct daio *daio) | ||
598 | { | ||
599 | unsigned long flags; | ||
600 | |||
601 | mgr->daio_disable(mgr, daio); | ||
602 | mgr->commit_write(mgr); | ||
603 | |||
604 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
605 | daio_mgr_put_rsc(&mgr->mgr, daio->type); | ||
606 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
607 | |||
608 | if (daio->type <= DAIO_OUT_MAX) { | ||
609 | dao_rsc_uninit(container_of(daio, struct dao, daio)); | ||
610 | kfree(container_of(daio, struct dao, daio)); | ||
611 | } else { | ||
612 | dai_rsc_uninit(container_of(daio, struct dai, daio)); | ||
613 | kfree(container_of(daio, struct dai, daio)); | ||
614 | } | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int daio_mgr_enb_daio(struct daio_mgr *mgr, struct daio *daio) | ||
620 | { | ||
621 | struct hw *hw = mgr->mgr.hw; | ||
622 | |||
623 | if (DAIO_OUT_MAX >= daio->type) { | ||
624 | hw->daio_mgr_enb_dao(mgr->mgr.ctrl_blk, | ||
625 | daio_device_index(daio->type, hw)); | ||
626 | } else { | ||
627 | hw->daio_mgr_enb_dai(mgr->mgr.ctrl_blk, | ||
628 | daio_device_index(daio->type, hw)); | ||
629 | } | ||
630 | return 0; | ||
631 | } | ||
632 | |||
633 | static int daio_mgr_dsb_daio(struct daio_mgr *mgr, struct daio *daio) | ||
634 | { | ||
635 | struct hw *hw = mgr->mgr.hw; | ||
636 | |||
637 | if (DAIO_OUT_MAX >= daio->type) { | ||
638 | hw->daio_mgr_dsb_dao(mgr->mgr.ctrl_blk, | ||
639 | daio_device_index(daio->type, hw)); | ||
640 | } else { | ||
641 | hw->daio_mgr_dsb_dai(mgr->mgr.ctrl_blk, | ||
642 | daio_device_index(daio->type, hw)); | ||
643 | } | ||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int daio_map_op(void *data, struct imapper *entry) | ||
648 | { | ||
649 | struct rsc_mgr *mgr = &((struct daio_mgr *)data)->mgr; | ||
650 | struct hw *hw = mgr->hw; | ||
651 | |||
652 | hw->daio_mgr_set_imaparc(mgr->ctrl_blk, entry->slot); | ||
653 | hw->daio_mgr_set_imapnxt(mgr->ctrl_blk, entry->next); | ||
654 | hw->daio_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr); | ||
655 | hw->daio_mgr_commit_write(mgr->hw, mgr->ctrl_blk); | ||
656 | |||
657 | return 0; | ||
658 | } | ||
659 | |||
660 | static int daio_imap_add(struct daio_mgr *mgr, struct imapper *entry) | ||
661 | { | ||
662 | unsigned long flags; | ||
663 | int err; | ||
664 | |||
665 | spin_lock_irqsave(&mgr->imap_lock, flags); | ||
666 | if ((0 == entry->addr) && (mgr->init_imap_added)) { | ||
667 | input_mapper_delete(&mgr->imappers, mgr->init_imap, | ||
668 | daio_map_op, mgr); | ||
669 | mgr->init_imap_added = 0; | ||
670 | } | ||
671 | err = input_mapper_add(&mgr->imappers, entry, daio_map_op, mgr); | ||
672 | spin_unlock_irqrestore(&mgr->imap_lock, flags); | ||
673 | |||
674 | return err; | ||
675 | } | ||
676 | |||
677 | static int daio_imap_delete(struct daio_mgr *mgr, struct imapper *entry) | ||
678 | { | ||
679 | unsigned long flags; | ||
680 | int err; | ||
681 | |||
682 | spin_lock_irqsave(&mgr->imap_lock, flags); | ||
683 | err = input_mapper_delete(&mgr->imappers, entry, daio_map_op, mgr); | ||
684 | if (list_empty(&mgr->imappers)) { | ||
685 | input_mapper_add(&mgr->imappers, mgr->init_imap, | ||
686 | daio_map_op, mgr); | ||
687 | mgr->init_imap_added = 1; | ||
688 | } | ||
689 | spin_unlock_irqrestore(&mgr->imap_lock, flags); | ||
690 | |||
691 | return err; | ||
692 | } | ||
693 | |||
694 | static int daio_mgr_commit_write(struct daio_mgr *mgr) | ||
695 | { | ||
696 | struct hw *hw = mgr->mgr.hw; | ||
697 | |||
698 | hw->daio_mgr_commit_write(hw, mgr->mgr.ctrl_blk); | ||
699 | return 0; | ||
700 | } | ||
701 | |||
702 | int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr) | ||
703 | { | ||
704 | int err, i; | ||
705 | struct daio_mgr *daio_mgr; | ||
706 | struct imapper *entry; | ||
707 | |||
708 | *rdaio_mgr = NULL; | ||
709 | daio_mgr = kzalloc(sizeof(*daio_mgr), GFP_KERNEL); | ||
710 | if (NULL == daio_mgr) | ||
711 | return -ENOMEM; | ||
712 | |||
713 | err = rsc_mgr_init(&daio_mgr->mgr, DAIO, DAIO_RESOURCE_NUM, hw); | ||
714 | if (err) | ||
715 | goto error1; | ||
716 | |||
717 | spin_lock_init(&daio_mgr->mgr_lock); | ||
718 | spin_lock_init(&daio_mgr->imap_lock); | ||
719 | INIT_LIST_HEAD(&daio_mgr->imappers); | ||
720 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
721 | if (NULL == entry) { | ||
722 | err = -ENOMEM; | ||
723 | goto error2; | ||
724 | } | ||
725 | entry->slot = entry->addr = entry->next = entry->user = 0; | ||
726 | list_add(&entry->list, &daio_mgr->imappers); | ||
727 | daio_mgr->init_imap = entry; | ||
728 | daio_mgr->init_imap_added = 1; | ||
729 | |||
730 | daio_mgr->get_daio = get_daio_rsc; | ||
731 | daio_mgr->put_daio = put_daio_rsc; | ||
732 | daio_mgr->daio_enable = daio_mgr_enb_daio; | ||
733 | daio_mgr->daio_disable = daio_mgr_dsb_daio; | ||
734 | daio_mgr->imap_add = daio_imap_add; | ||
735 | daio_mgr->imap_delete = daio_imap_delete; | ||
736 | daio_mgr->commit_write = daio_mgr_commit_write; | ||
737 | |||
738 | for (i = 0; i < 8; i++) { | ||
739 | ((struct hw *)hw)->daio_mgr_dsb_dao(daio_mgr->mgr.ctrl_blk, i); | ||
740 | ((struct hw *)hw)->daio_mgr_dsb_dai(daio_mgr->mgr.ctrl_blk, i); | ||
741 | } | ||
742 | ((struct hw *)hw)->daio_mgr_commit_write(hw, daio_mgr->mgr.ctrl_blk); | ||
743 | |||
744 | *rdaio_mgr = daio_mgr; | ||
745 | |||
746 | return 0; | ||
747 | |||
748 | error2: | ||
749 | rsc_mgr_uninit(&daio_mgr->mgr); | ||
750 | error1: | ||
751 | kfree(daio_mgr); | ||
752 | return err; | ||
753 | } | ||
754 | |||
755 | int daio_mgr_destroy(struct daio_mgr *daio_mgr) | ||
756 | { | ||
757 | unsigned long flags; | ||
758 | |||
759 | /* free daio input mapper list */ | ||
760 | spin_lock_irqsave(&daio_mgr->imap_lock, flags); | ||
761 | free_input_mapper_list(&daio_mgr->imappers); | ||
762 | spin_unlock_irqrestore(&daio_mgr->imap_lock, flags); | ||
763 | |||
764 | rsc_mgr_uninit(&daio_mgr->mgr); | ||
765 | kfree(daio_mgr); | ||
766 | |||
767 | return 0; | ||
768 | } | ||
769 | |||
diff --git a/sound/pci/ctxfi/ctdaio.h b/sound/pci/ctxfi/ctdaio.h new file mode 100644 index 000000000000..0f52ce571ee8 --- /dev/null +++ b/sound/pci/ctxfi/ctdaio.h | |||
@@ -0,0 +1,122 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctdaio.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of Digital Audio Input Output | ||
12 | * resource management object. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 23 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef CTDAIO_H | ||
20 | #define CTDAIO_H | ||
21 | |||
22 | #include "ctresource.h" | ||
23 | #include "ctimap.h" | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/list.h> | ||
26 | |||
27 | /* Define the descriptor of a daio resource */ | ||
28 | enum DAIOTYP { | ||
29 | LINEO1, | ||
30 | LINEO2, | ||
31 | LINEO3, | ||
32 | LINEO4, | ||
33 | SPDIFOO, /* S/PDIF Out (Flexijack/Optical) */ | ||
34 | LINEIM, | ||
35 | SPDIFIO, /* S/PDIF In (Flexijack/Optical) on the card */ | ||
36 | SPDIFI1, /* S/PDIF In on internal Drive Bay */ | ||
37 | NUM_DAIOTYP | ||
38 | }; | ||
39 | |||
40 | struct dao_rsc_ops; | ||
41 | struct dai_rsc_ops; | ||
42 | struct daio_mgr; | ||
43 | |||
44 | struct daio { | ||
45 | struct rsc rscl; /* Basic resource info for left TX/RX */ | ||
46 | struct rsc rscr; /* Basic resource info for right TX/RX */ | ||
47 | enum DAIOTYP type; | ||
48 | }; | ||
49 | |||
50 | struct dao { | ||
51 | struct daio daio; | ||
52 | struct dao_rsc_ops *ops; /* DAO specific operations */ | ||
53 | struct imapper **imappers; | ||
54 | struct daio_mgr *mgr; | ||
55 | void *hw; | ||
56 | void *ctrl_blk; | ||
57 | }; | ||
58 | |||
59 | struct dai { | ||
60 | struct daio daio; | ||
61 | struct dai_rsc_ops *ops; /* DAI specific operations */ | ||
62 | void *hw; | ||
63 | void *ctrl_blk; | ||
64 | }; | ||
65 | |||
66 | struct dao_desc { | ||
67 | unsigned int msr:4; | ||
68 | unsigned int passthru:1; | ||
69 | }; | ||
70 | |||
71 | struct dao_rsc_ops { | ||
72 | int (*set_spos)(struct dao *dao, unsigned int spos); | ||
73 | int (*commit_write)(struct dao *dao); | ||
74 | int (*get_spos)(struct dao *dao, unsigned int *spos); | ||
75 | int (*reinit)(struct dao *dao, const struct dao_desc *desc); | ||
76 | int (*set_left_input)(struct dao *dao, struct rsc *input); | ||
77 | int (*set_right_input)(struct dao *dao, struct rsc *input); | ||
78 | int (*clear_left_input)(struct dao *dao); | ||
79 | int (*clear_right_input)(struct dao *dao); | ||
80 | }; | ||
81 | |||
82 | struct dai_rsc_ops { | ||
83 | int (*set_srt_srcl)(struct dai *dai, struct rsc *src); | ||
84 | int (*set_srt_srcr)(struct dai *dai, struct rsc *src); | ||
85 | int (*set_srt_msr)(struct dai *dai, unsigned int msr); | ||
86 | int (*set_enb_src)(struct dai *dai, unsigned int enb); | ||
87 | int (*set_enb_srt)(struct dai *dai, unsigned int enb); | ||
88 | int (*commit_write)(struct dai *dai); | ||
89 | }; | ||
90 | |||
91 | /* Define daio resource request description info */ | ||
92 | struct daio_desc { | ||
93 | unsigned int type:4; | ||
94 | unsigned int msr:4; | ||
95 | unsigned int passthru:1; | ||
96 | }; | ||
97 | |||
98 | struct daio_mgr { | ||
99 | struct rsc_mgr mgr; /* Basic resource manager info */ | ||
100 | spinlock_t mgr_lock; | ||
101 | spinlock_t imap_lock; | ||
102 | struct list_head imappers; | ||
103 | struct imapper *init_imap; | ||
104 | unsigned int init_imap_added; | ||
105 | |||
106 | /* request one daio resource */ | ||
107 | int (*get_daio)(struct daio_mgr *mgr, | ||
108 | const struct daio_desc *desc, struct daio **rdaio); | ||
109 | /* return one daio resource */ | ||
110 | int (*put_daio)(struct daio_mgr *mgr, struct daio *daio); | ||
111 | int (*daio_enable)(struct daio_mgr *mgr, struct daio *daio); | ||
112 | int (*daio_disable)(struct daio_mgr *mgr, struct daio *daio); | ||
113 | int (*imap_add)(struct daio_mgr *mgr, struct imapper *entry); | ||
114 | int (*imap_delete)(struct daio_mgr *mgr, struct imapper *entry); | ||
115 | int (*commit_write)(struct daio_mgr *mgr); | ||
116 | }; | ||
117 | |||
118 | /* Constructor and destructor of daio resource manager */ | ||
119 | int daio_mgr_create(void *hw, struct daio_mgr **rdaio_mgr); | ||
120 | int daio_mgr_destroy(struct daio_mgr *daio_mgr); | ||
121 | |||
122 | #endif /* CTDAIO_H */ | ||
diff --git a/sound/pci/ctxfi/cthardware.c b/sound/pci/ctxfi/cthardware.c new file mode 100644 index 000000000000..8e64f4862e85 --- /dev/null +++ b/sound/pci/ctxfi/cthardware.c | |||
@@ -0,0 +1,91 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File cthardware.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of hardware access methord. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date Jun 26 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include "cthardware.h" | ||
19 | #include "cthw20k1.h" | ||
20 | #include "cthw20k2.h" | ||
21 | #include <linux/bug.h> | ||
22 | |||
23 | int __devinit create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, | ||
24 | enum CTCARDS model, struct hw **rhw) | ||
25 | { | ||
26 | int err; | ||
27 | |||
28 | switch (chip_type) { | ||
29 | case ATC20K1: | ||
30 | err = create_20k1_hw_obj(rhw); | ||
31 | break; | ||
32 | case ATC20K2: | ||
33 | err = create_20k2_hw_obj(rhw); | ||
34 | break; | ||
35 | default: | ||
36 | err = -ENODEV; | ||
37 | break; | ||
38 | } | ||
39 | if (err) | ||
40 | return err; | ||
41 | |||
42 | (*rhw)->pci = pci; | ||
43 | (*rhw)->chip_type = chip_type; | ||
44 | (*rhw)->model = model; | ||
45 | |||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | int destroy_hw_obj(struct hw *hw) | ||
50 | { | ||
51 | int err; | ||
52 | |||
53 | switch (hw->pci->device) { | ||
54 | case 0x0005: /* 20k1 device */ | ||
55 | err = destroy_20k1_hw_obj(hw); | ||
56 | break; | ||
57 | case 0x000B: /* 20k2 device */ | ||
58 | err = destroy_20k2_hw_obj(hw); | ||
59 | break; | ||
60 | default: | ||
61 | err = -ENODEV; | ||
62 | break; | ||
63 | } | ||
64 | |||
65 | return err; | ||
66 | } | ||
67 | |||
68 | unsigned int get_field(unsigned int data, unsigned int field) | ||
69 | { | ||
70 | int i; | ||
71 | |||
72 | BUG_ON(!field); | ||
73 | /* @field should always be greater than 0 */ | ||
74 | for (i = 0; !(field & (1 << i)); ) | ||
75 | i++; | ||
76 | |||
77 | return (data & field) >> i; | ||
78 | } | ||
79 | |||
80 | void set_field(unsigned int *data, unsigned int field, unsigned int value) | ||
81 | { | ||
82 | int i; | ||
83 | |||
84 | BUG_ON(!field); | ||
85 | /* @field should always be greater than 0 */ | ||
86 | for (i = 0; !(field & (1 << i)); ) | ||
87 | i++; | ||
88 | |||
89 | *data = (*data & (~field)) | ((value << i) & field); | ||
90 | } | ||
91 | |||
diff --git a/sound/pci/ctxfi/cthardware.h b/sound/pci/ctxfi/cthardware.h new file mode 100644 index 000000000000..4a8e04f090a4 --- /dev/null +++ b/sound/pci/ctxfi/cthardware.h | |||
@@ -0,0 +1,196 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File cthardware.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of hardware access methord. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date May 13 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef CTHARDWARE_H | ||
19 | #define CTHARDWARE_H | ||
20 | |||
21 | #include <linux/types.h> | ||
22 | #include <linux/pci.h> | ||
23 | |||
24 | enum CHIPTYP { | ||
25 | ATC20K1, | ||
26 | ATC20K2, | ||
27 | ATCNONE | ||
28 | }; | ||
29 | |||
30 | enum CTCARDS { | ||
31 | /* 20k1 models */ | ||
32 | CTSB055X, | ||
33 | CTSB073X, | ||
34 | CTUAA, | ||
35 | CT20K1_UNKNOWN, | ||
36 | /* 20k2 models */ | ||
37 | CTSB0760, | ||
38 | CTHENDRIX, | ||
39 | CTSB0880, | ||
40 | NUM_CTCARDS /* This should always be the last */ | ||
41 | }; | ||
42 | |||
43 | /* Type of input source for ADC */ | ||
44 | enum ADCSRC{ | ||
45 | ADC_MICIN, | ||
46 | ADC_LINEIN, | ||
47 | ADC_VIDEO, | ||
48 | ADC_AUX, | ||
49 | ADC_NONE /* Switch to digital input */ | ||
50 | }; | ||
51 | |||
52 | struct card_conf { | ||
53 | /* device virtual mem page table page physical addr | ||
54 | * (supporting one page table page now) */ | ||
55 | unsigned long vm_pgt_phys; | ||
56 | unsigned int rsr; /* reference sample rate in Hzs*/ | ||
57 | unsigned int msr; /* master sample rate in rsrs */ | ||
58 | }; | ||
59 | |||
60 | struct hw { | ||
61 | int (*card_init)(struct hw *hw, struct card_conf *info); | ||
62 | int (*card_stop)(struct hw *hw); | ||
63 | int (*pll_init)(struct hw *hw, unsigned int rsr); | ||
64 | int (*is_adc_source_selected)(struct hw *hw, enum ADCSRC source); | ||
65 | int (*select_adc_source)(struct hw *hw, enum ADCSRC source); | ||
66 | int (*have_digit_io_switch)(struct hw *hw); | ||
67 | |||
68 | /* SRC operations */ | ||
69 | int (*src_rsc_get_ctrl_blk)(void **rblk); | ||
70 | int (*src_rsc_put_ctrl_blk)(void *blk); | ||
71 | int (*src_set_state)(void *blk, unsigned int state); | ||
72 | int (*src_set_bm)(void *blk, unsigned int bm); | ||
73 | int (*src_set_rsr)(void *blk, unsigned int rsr); | ||
74 | int (*src_set_sf)(void *blk, unsigned int sf); | ||
75 | int (*src_set_wr)(void *blk, unsigned int wr); | ||
76 | int (*src_set_pm)(void *blk, unsigned int pm); | ||
77 | int (*src_set_rom)(void *blk, unsigned int rom); | ||
78 | int (*src_set_vo)(void *blk, unsigned int vo); | ||
79 | int (*src_set_st)(void *blk, unsigned int st); | ||
80 | int (*src_set_ie)(void *blk, unsigned int ie); | ||
81 | int (*src_set_ilsz)(void *blk, unsigned int ilsz); | ||
82 | int (*src_set_bp)(void *blk, unsigned int bp); | ||
83 | int (*src_set_cisz)(void *blk, unsigned int cisz); | ||
84 | int (*src_set_ca)(void *blk, unsigned int ca); | ||
85 | int (*src_set_sa)(void *blk, unsigned int sa); | ||
86 | int (*src_set_la)(void *blk, unsigned int la); | ||
87 | int (*src_set_pitch)(void *blk, unsigned int pitch); | ||
88 | int (*src_set_clear_zbufs)(void *blk, unsigned int clear); | ||
89 | int (*src_set_dirty)(void *blk, unsigned int flags); | ||
90 | int (*src_set_dirty_all)(void *blk); | ||
91 | int (*src_commit_write)(struct hw *hw, unsigned int idx, void *blk); | ||
92 | int (*src_get_ca)(struct hw *hw, unsigned int idx, void *blk); | ||
93 | unsigned int (*src_get_dirty)(void *blk); | ||
94 | unsigned int (*src_dirty_conj_mask)(void); | ||
95 | int (*src_mgr_get_ctrl_blk)(void **rblk); | ||
96 | int (*src_mgr_put_ctrl_blk)(void *blk); | ||
97 | /* syncly enable src @idx */ | ||
98 | int (*src_mgr_enbs_src)(void *blk, unsigned int idx); | ||
99 | /* enable src @idx */ | ||
100 | int (*src_mgr_enb_src)(void *blk, unsigned int idx); | ||
101 | /* disable src @idx */ | ||
102 | int (*src_mgr_dsb_src)(void *blk, unsigned int idx); | ||
103 | int (*src_mgr_commit_write)(struct hw *hw, void *blk); | ||
104 | |||
105 | /* SRC Input Mapper operations */ | ||
106 | int (*srcimp_mgr_get_ctrl_blk)(void **rblk); | ||
107 | int (*srcimp_mgr_put_ctrl_blk)(void *blk); | ||
108 | int (*srcimp_mgr_set_imaparc)(void *blk, unsigned int slot); | ||
109 | int (*srcimp_mgr_set_imapuser)(void *blk, unsigned int user); | ||
110 | int (*srcimp_mgr_set_imapnxt)(void *blk, unsigned int next); | ||
111 | int (*srcimp_mgr_set_imapaddr)(void *blk, unsigned int addr); | ||
112 | int (*srcimp_mgr_commit_write)(struct hw *hw, void *blk); | ||
113 | |||
114 | /* AMIXER operations */ | ||
115 | int (*amixer_rsc_get_ctrl_blk)(void **rblk); | ||
116 | int (*amixer_rsc_put_ctrl_blk)(void *blk); | ||
117 | int (*amixer_mgr_get_ctrl_blk)(void **rblk); | ||
118 | int (*amixer_mgr_put_ctrl_blk)(void *blk); | ||
119 | int (*amixer_set_mode)(void *blk, unsigned int mode); | ||
120 | int (*amixer_set_iv)(void *blk, unsigned int iv); | ||
121 | int (*amixer_set_x)(void *blk, unsigned int x); | ||
122 | int (*amixer_set_y)(void *blk, unsigned int y); | ||
123 | int (*amixer_set_sadr)(void *blk, unsigned int sadr); | ||
124 | int (*amixer_set_se)(void *blk, unsigned int se); | ||
125 | int (*amixer_set_dirty)(void *blk, unsigned int flags); | ||
126 | int (*amixer_set_dirty_all)(void *blk); | ||
127 | int (*amixer_commit_write)(struct hw *hw, unsigned int idx, void *blk); | ||
128 | int (*amixer_get_y)(void *blk); | ||
129 | unsigned int (*amixer_get_dirty)(void *blk); | ||
130 | |||
131 | /* DAIO operations */ | ||
132 | int (*dai_get_ctrl_blk)(void **rblk); | ||
133 | int (*dai_put_ctrl_blk)(void *blk); | ||
134 | int (*dai_srt_set_srco)(void *blk, unsigned int src); | ||
135 | int (*dai_srt_set_srcm)(void *blk, unsigned int src); | ||
136 | int (*dai_srt_set_rsr)(void *blk, unsigned int rsr); | ||
137 | int (*dai_srt_set_drat)(void *blk, unsigned int drat); | ||
138 | int (*dai_srt_set_ec)(void *blk, unsigned int ec); | ||
139 | int (*dai_srt_set_et)(void *blk, unsigned int et); | ||
140 | int (*dai_commit_write)(struct hw *hw, unsigned int idx, void *blk); | ||
141 | int (*dao_get_ctrl_blk)(void **rblk); | ||
142 | int (*dao_put_ctrl_blk)(void *blk); | ||
143 | int (*dao_set_spos)(void *blk, unsigned int spos); | ||
144 | int (*dao_commit_write)(struct hw *hw, unsigned int idx, void *blk); | ||
145 | int (*dao_get_spos)(void *blk, unsigned int *spos); | ||
146 | |||
147 | int (*daio_mgr_get_ctrl_blk)(struct hw *hw, void **rblk); | ||
148 | int (*daio_mgr_put_ctrl_blk)(void *blk); | ||
149 | int (*daio_mgr_enb_dai)(void *blk, unsigned int idx); | ||
150 | int (*daio_mgr_dsb_dai)(void *blk, unsigned int idx); | ||
151 | int (*daio_mgr_enb_dao)(void *blk, unsigned int idx); | ||
152 | int (*daio_mgr_dsb_dao)(void *blk, unsigned int idx); | ||
153 | int (*daio_mgr_dao_init)(void *blk, unsigned int idx, | ||
154 | unsigned int conf); | ||
155 | int (*daio_mgr_set_imaparc)(void *blk, unsigned int slot); | ||
156 | int (*daio_mgr_set_imapnxt)(void *blk, unsigned int next); | ||
157 | int (*daio_mgr_set_imapaddr)(void *blk, unsigned int addr); | ||
158 | int (*daio_mgr_commit_write)(struct hw *hw, void *blk); | ||
159 | |||
160 | int (*set_timer_irq)(struct hw *hw, int enable); | ||
161 | int (*set_timer_tick)(struct hw *hw, unsigned int tick); | ||
162 | unsigned int (*get_wc)(struct hw *hw); | ||
163 | |||
164 | void (*irq_callback)(void *data, unsigned int bit); | ||
165 | void *irq_callback_data; | ||
166 | |||
167 | struct pci_dev *pci; /* the pci kernel structure of this card */ | ||
168 | int irq; | ||
169 | unsigned long io_base; | ||
170 | unsigned long mem_base; | ||
171 | |||
172 | enum CHIPTYP chip_type; | ||
173 | enum CTCARDS model; | ||
174 | }; | ||
175 | |||
176 | int create_hw_obj(struct pci_dev *pci, enum CHIPTYP chip_type, | ||
177 | enum CTCARDS model, struct hw **rhw); | ||
178 | int destroy_hw_obj(struct hw *hw); | ||
179 | |||
180 | unsigned int get_field(unsigned int data, unsigned int field); | ||
181 | void set_field(unsigned int *data, unsigned int field, unsigned int value); | ||
182 | |||
183 | /* IRQ bits */ | ||
184 | #define PLL_INT (1 << 10) /* PLL input-clock out-of-range */ | ||
185 | #define FI_INT (1 << 9) /* forced interrupt */ | ||
186 | #define IT_INT (1 << 8) /* timer interrupt */ | ||
187 | #define PCI_INT (1 << 7) /* PCI bus error pending */ | ||
188 | #define URT_INT (1 << 6) /* UART Tx/Rx */ | ||
189 | #define GPI_INT (1 << 5) /* GPI pin */ | ||
190 | #define MIX_INT (1 << 4) /* mixer parameter segment FIFO channels */ | ||
191 | #define DAI_INT (1 << 3) /* DAI (SR-tracker or SPDIF-receiver) */ | ||
192 | #define TP_INT (1 << 2) /* transport priority queue */ | ||
193 | #define DSP_INT (1 << 1) /* DSP */ | ||
194 | #define SRC_INT (1 << 0) /* SRC channels */ | ||
195 | |||
196 | #endif /* CTHARDWARE_H */ | ||
diff --git a/sound/pci/ctxfi/cthw20k1.c b/sound/pci/ctxfi/cthw20k1.c new file mode 100644 index 000000000000..cb69d9ddfbe3 --- /dev/null +++ b/sound/pci/ctxfi/cthw20k1.c | |||
@@ -0,0 +1,2248 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File cthw20k1.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of hardware access methord for 20k1. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date Jun 24 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/types.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/spinlock.h> | ||
24 | #include <linux/kernel.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/delay.h> | ||
27 | #include "cthw20k1.h" | ||
28 | #include "ct20k1reg.h" | ||
29 | |||
30 | #if BITS_PER_LONG == 32 | ||
31 | #define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ | ||
32 | #else | ||
33 | #define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ | ||
34 | #endif | ||
35 | |||
36 | struct hw20k1 { | ||
37 | struct hw hw; | ||
38 | spinlock_t reg_20k1_lock; | ||
39 | spinlock_t reg_pci_lock; | ||
40 | }; | ||
41 | |||
42 | static u32 hw_read_20kx(struct hw *hw, u32 reg); | ||
43 | static void hw_write_20kx(struct hw *hw, u32 reg, u32 data); | ||
44 | static u32 hw_read_pci(struct hw *hw, u32 reg); | ||
45 | static void hw_write_pci(struct hw *hw, u32 reg, u32 data); | ||
46 | |||
47 | /* | ||
48 | * Type definition block. | ||
49 | * The layout of control structures can be directly applied on 20k2 chip. | ||
50 | */ | ||
51 | |||
52 | /* | ||
53 | * SRC control block definitions. | ||
54 | */ | ||
55 | |||
56 | /* SRC resource control block */ | ||
57 | #define SRCCTL_STATE 0x00000007 | ||
58 | #define SRCCTL_BM 0x00000008 | ||
59 | #define SRCCTL_RSR 0x00000030 | ||
60 | #define SRCCTL_SF 0x000001C0 | ||
61 | #define SRCCTL_WR 0x00000200 | ||
62 | #define SRCCTL_PM 0x00000400 | ||
63 | #define SRCCTL_ROM 0x00001800 | ||
64 | #define SRCCTL_VO 0x00002000 | ||
65 | #define SRCCTL_ST 0x00004000 | ||
66 | #define SRCCTL_IE 0x00008000 | ||
67 | #define SRCCTL_ILSZ 0x000F0000 | ||
68 | #define SRCCTL_BP 0x00100000 | ||
69 | |||
70 | #define SRCCCR_CISZ 0x000007FF | ||
71 | #define SRCCCR_CWA 0x001FF800 | ||
72 | #define SRCCCR_D 0x00200000 | ||
73 | #define SRCCCR_RS 0x01C00000 | ||
74 | #define SRCCCR_NAL 0x3E000000 | ||
75 | #define SRCCCR_RA 0xC0000000 | ||
76 | |||
77 | #define SRCCA_CA 0x03FFFFFF | ||
78 | #define SRCCA_RS 0x1C000000 | ||
79 | #define SRCCA_NAL 0xE0000000 | ||
80 | |||
81 | #define SRCSA_SA 0x03FFFFFF | ||
82 | |||
83 | #define SRCLA_LA 0x03FFFFFF | ||
84 | |||
85 | /* Mixer Parameter Ring ram Low and Hight register. | ||
86 | * Fixed-point value in 8.24 format for parameter channel */ | ||
87 | #define MPRLH_PITCH 0xFFFFFFFF | ||
88 | |||
89 | /* SRC resource register dirty flags */ | ||
90 | union src_dirty { | ||
91 | struct { | ||
92 | u16 ctl:1; | ||
93 | u16 ccr:1; | ||
94 | u16 sa:1; | ||
95 | u16 la:1; | ||
96 | u16 ca:1; | ||
97 | u16 mpr:1; | ||
98 | u16 czbfs:1; /* Clear Z-Buffers */ | ||
99 | u16 rsv:9; | ||
100 | } bf; | ||
101 | u16 data; | ||
102 | }; | ||
103 | |||
104 | struct src_rsc_ctrl_blk { | ||
105 | unsigned int ctl; | ||
106 | unsigned int ccr; | ||
107 | unsigned int ca; | ||
108 | unsigned int sa; | ||
109 | unsigned int la; | ||
110 | unsigned int mpr; | ||
111 | union src_dirty dirty; | ||
112 | }; | ||
113 | |||
114 | /* SRC manager control block */ | ||
115 | union src_mgr_dirty { | ||
116 | struct { | ||
117 | u16 enb0:1; | ||
118 | u16 enb1:1; | ||
119 | u16 enb2:1; | ||
120 | u16 enb3:1; | ||
121 | u16 enb4:1; | ||
122 | u16 enb5:1; | ||
123 | u16 enb6:1; | ||
124 | u16 enb7:1; | ||
125 | u16 enbsa:1; | ||
126 | u16 rsv:7; | ||
127 | } bf; | ||
128 | u16 data; | ||
129 | }; | ||
130 | |||
131 | struct src_mgr_ctrl_blk { | ||
132 | unsigned int enbsa; | ||
133 | unsigned int enb[8]; | ||
134 | union src_mgr_dirty dirty; | ||
135 | }; | ||
136 | |||
137 | /* SRCIMP manager control block */ | ||
138 | #define SRCAIM_ARC 0x00000FFF | ||
139 | #define SRCAIM_NXT 0x00FF0000 | ||
140 | #define SRCAIM_SRC 0xFF000000 | ||
141 | |||
142 | struct srcimap { | ||
143 | unsigned int srcaim; | ||
144 | unsigned int idx; | ||
145 | }; | ||
146 | |||
147 | /* SRCIMP manager register dirty flags */ | ||
148 | union srcimp_mgr_dirty { | ||
149 | struct { | ||
150 | u16 srcimap:1; | ||
151 | u16 rsv:15; | ||
152 | } bf; | ||
153 | u16 data; | ||
154 | }; | ||
155 | |||
156 | struct srcimp_mgr_ctrl_blk { | ||
157 | struct srcimap srcimap; | ||
158 | union srcimp_mgr_dirty dirty; | ||
159 | }; | ||
160 | |||
161 | /* | ||
162 | * Function implementation block. | ||
163 | */ | ||
164 | |||
165 | static int src_get_rsc_ctrl_blk(void **rblk) | ||
166 | { | ||
167 | struct src_rsc_ctrl_blk *blk; | ||
168 | |||
169 | *rblk = NULL; | ||
170 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
171 | if (NULL == blk) | ||
172 | return -ENOMEM; | ||
173 | |||
174 | *rblk = blk; | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | static int src_put_rsc_ctrl_blk(void *blk) | ||
180 | { | ||
181 | kfree((struct src_rsc_ctrl_blk *)blk); | ||
182 | |||
183 | return 0; | ||
184 | } | ||
185 | |||
186 | static int src_set_state(void *blk, unsigned int state) | ||
187 | { | ||
188 | struct src_rsc_ctrl_blk *ctl = blk; | ||
189 | |||
190 | set_field(&ctl->ctl, SRCCTL_STATE, state); | ||
191 | ctl->dirty.bf.ctl = 1; | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | static int src_set_bm(void *blk, unsigned int bm) | ||
196 | { | ||
197 | struct src_rsc_ctrl_blk *ctl = blk; | ||
198 | |||
199 | set_field(&ctl->ctl, SRCCTL_BM, bm); | ||
200 | ctl->dirty.bf.ctl = 1; | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int src_set_rsr(void *blk, unsigned int rsr) | ||
205 | { | ||
206 | struct src_rsc_ctrl_blk *ctl = blk; | ||
207 | |||
208 | set_field(&ctl->ctl, SRCCTL_RSR, rsr); | ||
209 | ctl->dirty.bf.ctl = 1; | ||
210 | return 0; | ||
211 | } | ||
212 | |||
213 | static int src_set_sf(void *blk, unsigned int sf) | ||
214 | { | ||
215 | struct src_rsc_ctrl_blk *ctl = blk; | ||
216 | |||
217 | set_field(&ctl->ctl, SRCCTL_SF, sf); | ||
218 | ctl->dirty.bf.ctl = 1; | ||
219 | return 0; | ||
220 | } | ||
221 | |||
222 | static int src_set_wr(void *blk, unsigned int wr) | ||
223 | { | ||
224 | struct src_rsc_ctrl_blk *ctl = blk; | ||
225 | |||
226 | set_field(&ctl->ctl, SRCCTL_WR, wr); | ||
227 | ctl->dirty.bf.ctl = 1; | ||
228 | return 0; | ||
229 | } | ||
230 | |||
231 | static int src_set_pm(void *blk, unsigned int pm) | ||
232 | { | ||
233 | struct src_rsc_ctrl_blk *ctl = blk; | ||
234 | |||
235 | set_field(&ctl->ctl, SRCCTL_PM, pm); | ||
236 | ctl->dirty.bf.ctl = 1; | ||
237 | return 0; | ||
238 | } | ||
239 | |||
240 | static int src_set_rom(void *blk, unsigned int rom) | ||
241 | { | ||
242 | struct src_rsc_ctrl_blk *ctl = blk; | ||
243 | |||
244 | set_field(&ctl->ctl, SRCCTL_ROM, rom); | ||
245 | ctl->dirty.bf.ctl = 1; | ||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static int src_set_vo(void *blk, unsigned int vo) | ||
250 | { | ||
251 | struct src_rsc_ctrl_blk *ctl = blk; | ||
252 | |||
253 | set_field(&ctl->ctl, SRCCTL_VO, vo); | ||
254 | ctl->dirty.bf.ctl = 1; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int src_set_st(void *blk, unsigned int st) | ||
259 | { | ||
260 | struct src_rsc_ctrl_blk *ctl = blk; | ||
261 | |||
262 | set_field(&ctl->ctl, SRCCTL_ST, st); | ||
263 | ctl->dirty.bf.ctl = 1; | ||
264 | return 0; | ||
265 | } | ||
266 | |||
267 | static int src_set_ie(void *blk, unsigned int ie) | ||
268 | { | ||
269 | struct src_rsc_ctrl_blk *ctl = blk; | ||
270 | |||
271 | set_field(&ctl->ctl, SRCCTL_IE, ie); | ||
272 | ctl->dirty.bf.ctl = 1; | ||
273 | return 0; | ||
274 | } | ||
275 | |||
276 | static int src_set_ilsz(void *blk, unsigned int ilsz) | ||
277 | { | ||
278 | struct src_rsc_ctrl_blk *ctl = blk; | ||
279 | |||
280 | set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz); | ||
281 | ctl->dirty.bf.ctl = 1; | ||
282 | return 0; | ||
283 | } | ||
284 | |||
285 | static int src_set_bp(void *blk, unsigned int bp) | ||
286 | { | ||
287 | struct src_rsc_ctrl_blk *ctl = blk; | ||
288 | |||
289 | set_field(&ctl->ctl, SRCCTL_BP, bp); | ||
290 | ctl->dirty.bf.ctl = 1; | ||
291 | return 0; | ||
292 | } | ||
293 | |||
294 | static int src_set_cisz(void *blk, unsigned int cisz) | ||
295 | { | ||
296 | struct src_rsc_ctrl_blk *ctl = blk; | ||
297 | |||
298 | set_field(&ctl->ccr, SRCCCR_CISZ, cisz); | ||
299 | ctl->dirty.bf.ccr = 1; | ||
300 | return 0; | ||
301 | } | ||
302 | |||
303 | static int src_set_ca(void *blk, unsigned int ca) | ||
304 | { | ||
305 | struct src_rsc_ctrl_blk *ctl = blk; | ||
306 | |||
307 | set_field(&ctl->ca, SRCCA_CA, ca); | ||
308 | ctl->dirty.bf.ca = 1; | ||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | static int src_set_sa(void *blk, unsigned int sa) | ||
313 | { | ||
314 | struct src_rsc_ctrl_blk *ctl = blk; | ||
315 | |||
316 | set_field(&ctl->sa, SRCSA_SA, sa); | ||
317 | ctl->dirty.bf.sa = 1; | ||
318 | return 0; | ||
319 | } | ||
320 | |||
321 | static int src_set_la(void *blk, unsigned int la) | ||
322 | { | ||
323 | struct src_rsc_ctrl_blk *ctl = blk; | ||
324 | |||
325 | set_field(&ctl->la, SRCLA_LA, la); | ||
326 | ctl->dirty.bf.la = 1; | ||
327 | return 0; | ||
328 | } | ||
329 | |||
330 | static int src_set_pitch(void *blk, unsigned int pitch) | ||
331 | { | ||
332 | struct src_rsc_ctrl_blk *ctl = blk; | ||
333 | |||
334 | set_field(&ctl->mpr, MPRLH_PITCH, pitch); | ||
335 | ctl->dirty.bf.mpr = 1; | ||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static int src_set_clear_zbufs(void *blk, unsigned int clear) | ||
340 | { | ||
341 | ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0); | ||
342 | return 0; | ||
343 | } | ||
344 | |||
345 | static int src_set_dirty(void *blk, unsigned int flags) | ||
346 | { | ||
347 | ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); | ||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static int src_set_dirty_all(void *blk) | ||
352 | { | ||
353 | ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); | ||
354 | return 0; | ||
355 | } | ||
356 | |||
357 | #define AR_SLOT_SIZE 4096 | ||
358 | #define AR_SLOT_BLOCK_SIZE 16 | ||
359 | #define AR_PTS_PITCH 6 | ||
360 | #define AR_PARAM_SRC_OFFSET 0x60 | ||
361 | |||
362 | static unsigned int src_param_pitch_mixer(unsigned int src_idx) | ||
363 | { | ||
364 | return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE | ||
365 | - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE; | ||
366 | |||
367 | } | ||
368 | |||
369 | static int src_commit_write(struct hw *hw, unsigned int idx, void *blk) | ||
370 | { | ||
371 | struct src_rsc_ctrl_blk *ctl = blk; | ||
372 | int i; | ||
373 | |||
374 | if (ctl->dirty.bf.czbfs) { | ||
375 | /* Clear Z-Buffer registers */ | ||
376 | for (i = 0; i < 8; i++) | ||
377 | hw_write_20kx(hw, SRCUPZ+idx*0x100+i*0x4, 0); | ||
378 | |||
379 | for (i = 0; i < 4; i++) | ||
380 | hw_write_20kx(hw, SRCDN0Z+idx*0x100+i*0x4, 0); | ||
381 | |||
382 | for (i = 0; i < 8; i++) | ||
383 | hw_write_20kx(hw, SRCDN1Z+idx*0x100+i*0x4, 0); | ||
384 | |||
385 | ctl->dirty.bf.czbfs = 0; | ||
386 | } | ||
387 | if (ctl->dirty.bf.mpr) { | ||
388 | /* Take the parameter mixer resource in the same group as that | ||
389 | * the idx src is in for simplicity. Unlike src, all conjugate | ||
390 | * parameter mixer resources must be programmed for | ||
391 | * corresponding conjugate src resources. */ | ||
392 | unsigned int pm_idx = src_param_pitch_mixer(idx); | ||
393 | hw_write_20kx(hw, PRING_LO_HI+4*pm_idx, ctl->mpr); | ||
394 | hw_write_20kx(hw, PMOPLO+8*pm_idx, 0x3); | ||
395 | hw_write_20kx(hw, PMOPHI+8*pm_idx, 0x0); | ||
396 | ctl->dirty.bf.mpr = 0; | ||
397 | } | ||
398 | if (ctl->dirty.bf.sa) { | ||
399 | hw_write_20kx(hw, SRCSA+idx*0x100, ctl->sa); | ||
400 | ctl->dirty.bf.sa = 0; | ||
401 | } | ||
402 | if (ctl->dirty.bf.la) { | ||
403 | hw_write_20kx(hw, SRCLA+idx*0x100, ctl->la); | ||
404 | ctl->dirty.bf.la = 0; | ||
405 | } | ||
406 | if (ctl->dirty.bf.ca) { | ||
407 | hw_write_20kx(hw, SRCCA+idx*0x100, ctl->ca); | ||
408 | ctl->dirty.bf.ca = 0; | ||
409 | } | ||
410 | |||
411 | /* Write srccf register */ | ||
412 | hw_write_20kx(hw, SRCCF+idx*0x100, 0x0); | ||
413 | |||
414 | if (ctl->dirty.bf.ccr) { | ||
415 | hw_write_20kx(hw, SRCCCR+idx*0x100, ctl->ccr); | ||
416 | ctl->dirty.bf.ccr = 0; | ||
417 | } | ||
418 | if (ctl->dirty.bf.ctl) { | ||
419 | hw_write_20kx(hw, SRCCTL+idx*0x100, ctl->ctl); | ||
420 | ctl->dirty.bf.ctl = 0; | ||
421 | } | ||
422 | |||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static int src_get_ca(struct hw *hw, unsigned int idx, void *blk) | ||
427 | { | ||
428 | struct src_rsc_ctrl_blk *ctl = blk; | ||
429 | |||
430 | ctl->ca = hw_read_20kx(hw, SRCCA+idx*0x100); | ||
431 | ctl->dirty.bf.ca = 0; | ||
432 | |||
433 | return get_field(ctl->ca, SRCCA_CA); | ||
434 | } | ||
435 | |||
436 | static unsigned int src_get_dirty(void *blk) | ||
437 | { | ||
438 | return ((struct src_rsc_ctrl_blk *)blk)->dirty.data; | ||
439 | } | ||
440 | |||
441 | static unsigned int src_dirty_conj_mask(void) | ||
442 | { | ||
443 | return 0x20; | ||
444 | } | ||
445 | |||
446 | static int src_mgr_enbs_src(void *blk, unsigned int idx) | ||
447 | { | ||
448 | ((struct src_mgr_ctrl_blk *)blk)->enbsa = ~(0x0); | ||
449 | ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1; | ||
450 | ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); | ||
451 | return 0; | ||
452 | } | ||
453 | |||
454 | static int src_mgr_enb_src(void *blk, unsigned int idx) | ||
455 | { | ||
456 | ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); | ||
457 | ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); | ||
458 | return 0; | ||
459 | } | ||
460 | |||
461 | static int src_mgr_dsb_src(void *blk, unsigned int idx) | ||
462 | { | ||
463 | ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32)); | ||
464 | ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); | ||
465 | return 0; | ||
466 | } | ||
467 | |||
468 | static int src_mgr_commit_write(struct hw *hw, void *blk) | ||
469 | { | ||
470 | struct src_mgr_ctrl_blk *ctl = blk; | ||
471 | int i; | ||
472 | unsigned int ret; | ||
473 | |||
474 | if (ctl->dirty.bf.enbsa) { | ||
475 | do { | ||
476 | ret = hw_read_20kx(hw, SRCENBSTAT); | ||
477 | } while (ret & 0x1); | ||
478 | hw_write_20kx(hw, SRCENBS, ctl->enbsa); | ||
479 | ctl->dirty.bf.enbsa = 0; | ||
480 | } | ||
481 | for (i = 0; i < 8; i++) { | ||
482 | if ((ctl->dirty.data & (0x1 << i))) { | ||
483 | hw_write_20kx(hw, SRCENB+(i*0x100), ctl->enb[i]); | ||
484 | ctl->dirty.data &= ~(0x1 << i); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | return 0; | ||
489 | } | ||
490 | |||
491 | static int src_mgr_get_ctrl_blk(void **rblk) | ||
492 | { | ||
493 | struct src_mgr_ctrl_blk *blk; | ||
494 | |||
495 | *rblk = NULL; | ||
496 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
497 | if (NULL == blk) | ||
498 | return -ENOMEM; | ||
499 | |||
500 | *rblk = blk; | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int src_mgr_put_ctrl_blk(void *blk) | ||
506 | { | ||
507 | kfree((struct src_mgr_ctrl_blk *)blk); | ||
508 | |||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | static int srcimp_mgr_get_ctrl_blk(void **rblk) | ||
513 | { | ||
514 | struct srcimp_mgr_ctrl_blk *blk; | ||
515 | |||
516 | *rblk = NULL; | ||
517 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
518 | if (NULL == blk) | ||
519 | return -ENOMEM; | ||
520 | |||
521 | *rblk = blk; | ||
522 | |||
523 | return 0; | ||
524 | } | ||
525 | |||
526 | static int srcimp_mgr_put_ctrl_blk(void *blk) | ||
527 | { | ||
528 | kfree((struct srcimp_mgr_ctrl_blk *)blk); | ||
529 | |||
530 | return 0; | ||
531 | } | ||
532 | |||
533 | static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot) | ||
534 | { | ||
535 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
536 | |||
537 | set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot); | ||
538 | ctl->dirty.bf.srcimap = 1; | ||
539 | return 0; | ||
540 | } | ||
541 | |||
542 | static int srcimp_mgr_set_imapuser(void *blk, unsigned int user) | ||
543 | { | ||
544 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
545 | |||
546 | set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user); | ||
547 | ctl->dirty.bf.srcimap = 1; | ||
548 | return 0; | ||
549 | } | ||
550 | |||
551 | static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next) | ||
552 | { | ||
553 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
554 | |||
555 | set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next); | ||
556 | ctl->dirty.bf.srcimap = 1; | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr) | ||
561 | { | ||
562 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
563 | |||
564 | ctl->srcimap.idx = addr; | ||
565 | ctl->dirty.bf.srcimap = 1; | ||
566 | return 0; | ||
567 | } | ||
568 | |||
569 | static int srcimp_mgr_commit_write(struct hw *hw, void *blk) | ||
570 | { | ||
571 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
572 | |||
573 | if (ctl->dirty.bf.srcimap) { | ||
574 | hw_write_20kx(hw, SRCIMAP+ctl->srcimap.idx*0x100, | ||
575 | ctl->srcimap.srcaim); | ||
576 | ctl->dirty.bf.srcimap = 0; | ||
577 | } | ||
578 | |||
579 | return 0; | ||
580 | } | ||
581 | |||
582 | /* | ||
583 | * AMIXER control block definitions. | ||
584 | */ | ||
585 | |||
586 | #define AMOPLO_M 0x00000003 | ||
587 | #define AMOPLO_X 0x0003FFF0 | ||
588 | #define AMOPLO_Y 0xFFFC0000 | ||
589 | |||
590 | #define AMOPHI_SADR 0x000000FF | ||
591 | #define AMOPHI_SE 0x80000000 | ||
592 | |||
593 | /* AMIXER resource register dirty flags */ | ||
594 | union amixer_dirty { | ||
595 | struct { | ||
596 | u16 amoplo:1; | ||
597 | u16 amophi:1; | ||
598 | u16 rsv:14; | ||
599 | } bf; | ||
600 | u16 data; | ||
601 | }; | ||
602 | |||
603 | /* AMIXER resource control block */ | ||
604 | struct amixer_rsc_ctrl_blk { | ||
605 | unsigned int amoplo; | ||
606 | unsigned int amophi; | ||
607 | union amixer_dirty dirty; | ||
608 | }; | ||
609 | |||
610 | static int amixer_set_mode(void *blk, unsigned int mode) | ||
611 | { | ||
612 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
613 | |||
614 | set_field(&ctl->amoplo, AMOPLO_M, mode); | ||
615 | ctl->dirty.bf.amoplo = 1; | ||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int amixer_set_iv(void *blk, unsigned int iv) | ||
620 | { | ||
621 | /* 20k1 amixer does not have this field */ | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static int amixer_set_x(void *blk, unsigned int x) | ||
626 | { | ||
627 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
628 | |||
629 | set_field(&ctl->amoplo, AMOPLO_X, x); | ||
630 | ctl->dirty.bf.amoplo = 1; | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static int amixer_set_y(void *blk, unsigned int y) | ||
635 | { | ||
636 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
637 | |||
638 | set_field(&ctl->amoplo, AMOPLO_Y, y); | ||
639 | ctl->dirty.bf.amoplo = 1; | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static int amixer_set_sadr(void *blk, unsigned int sadr) | ||
644 | { | ||
645 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
646 | |||
647 | set_field(&ctl->amophi, AMOPHI_SADR, sadr); | ||
648 | ctl->dirty.bf.amophi = 1; | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int amixer_set_se(void *blk, unsigned int se) | ||
653 | { | ||
654 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
655 | |||
656 | set_field(&ctl->amophi, AMOPHI_SE, se); | ||
657 | ctl->dirty.bf.amophi = 1; | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static int amixer_set_dirty(void *blk, unsigned int flags) | ||
662 | { | ||
663 | ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int amixer_set_dirty_all(void *blk) | ||
668 | { | ||
669 | ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk) | ||
674 | { | ||
675 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
676 | |||
677 | if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) { | ||
678 | hw_write_20kx(hw, AMOPLO+idx*8, ctl->amoplo); | ||
679 | ctl->dirty.bf.amoplo = 0; | ||
680 | hw_write_20kx(hw, AMOPHI+idx*8, ctl->amophi); | ||
681 | ctl->dirty.bf.amophi = 0; | ||
682 | } | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static int amixer_get_y(void *blk) | ||
688 | { | ||
689 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
690 | |||
691 | return get_field(ctl->amoplo, AMOPLO_Y); | ||
692 | } | ||
693 | |||
694 | static unsigned int amixer_get_dirty(void *blk) | ||
695 | { | ||
696 | return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data; | ||
697 | } | ||
698 | |||
699 | static int amixer_rsc_get_ctrl_blk(void **rblk) | ||
700 | { | ||
701 | struct amixer_rsc_ctrl_blk *blk; | ||
702 | |||
703 | *rblk = NULL; | ||
704 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
705 | if (NULL == blk) | ||
706 | return -ENOMEM; | ||
707 | |||
708 | *rblk = blk; | ||
709 | |||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | static int amixer_rsc_put_ctrl_blk(void *blk) | ||
714 | { | ||
715 | kfree((struct amixer_rsc_ctrl_blk *)blk); | ||
716 | |||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | static int amixer_mgr_get_ctrl_blk(void **rblk) | ||
721 | { | ||
722 | /*amixer_mgr_ctrl_blk_t *blk;*/ | ||
723 | |||
724 | *rblk = NULL; | ||
725 | /*blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
726 | if (NULL == blk) | ||
727 | return -ENOMEM; | ||
728 | |||
729 | *rblk = blk;*/ | ||
730 | |||
731 | return 0; | ||
732 | } | ||
733 | |||
734 | static int amixer_mgr_put_ctrl_blk(void *blk) | ||
735 | { | ||
736 | /*kfree((amixer_mgr_ctrl_blk_t *)blk);*/ | ||
737 | |||
738 | return 0; | ||
739 | } | ||
740 | |||
741 | /* | ||
742 | * DAIO control block definitions. | ||
743 | */ | ||
744 | |||
745 | /* Receiver Sample Rate Tracker Control register */ | ||
746 | #define SRTCTL_SRCR 0x000000FF | ||
747 | #define SRTCTL_SRCL 0x0000FF00 | ||
748 | #define SRTCTL_RSR 0x00030000 | ||
749 | #define SRTCTL_DRAT 0x000C0000 | ||
750 | #define SRTCTL_RLE 0x10000000 | ||
751 | #define SRTCTL_RLP 0x20000000 | ||
752 | #define SRTCTL_EC 0x40000000 | ||
753 | #define SRTCTL_ET 0x80000000 | ||
754 | |||
755 | /* DAIO Receiver register dirty flags */ | ||
756 | union dai_dirty { | ||
757 | struct { | ||
758 | u16 srtctl:1; | ||
759 | u16 rsv:15; | ||
760 | } bf; | ||
761 | u16 data; | ||
762 | }; | ||
763 | |||
764 | /* DAIO Receiver control block */ | ||
765 | struct dai_ctrl_blk { | ||
766 | unsigned int srtctl; | ||
767 | union dai_dirty dirty; | ||
768 | }; | ||
769 | |||
770 | /* S/PDIF Transmitter register dirty flags */ | ||
771 | union dao_dirty { | ||
772 | struct { | ||
773 | u16 spos:1; | ||
774 | u16 rsv:15; | ||
775 | } bf; | ||
776 | u16 data; | ||
777 | }; | ||
778 | |||
779 | /* S/PDIF Transmitter control block */ | ||
780 | struct dao_ctrl_blk { | ||
781 | unsigned int spos; /* S/PDIF Output Channel Status Register */ | ||
782 | union dao_dirty dirty; | ||
783 | }; | ||
784 | |||
785 | /* Audio Input Mapper RAM */ | ||
786 | #define AIM_ARC 0x00000FFF | ||
787 | #define AIM_NXT 0x007F0000 | ||
788 | |||
789 | struct daoimap { | ||
790 | unsigned int aim; | ||
791 | unsigned int idx; | ||
792 | }; | ||
793 | |||
794 | /* I2S Transmitter/Receiver Control register */ | ||
795 | #define I2SCTL_EA 0x00000004 | ||
796 | #define I2SCTL_EI 0x00000010 | ||
797 | |||
798 | /* S/PDIF Transmitter Control register */ | ||
799 | #define SPOCTL_OE 0x00000001 | ||
800 | #define SPOCTL_OS 0x0000000E | ||
801 | #define SPOCTL_RIV 0x00000010 | ||
802 | #define SPOCTL_LIV 0x00000020 | ||
803 | #define SPOCTL_SR 0x000000C0 | ||
804 | |||
805 | /* S/PDIF Receiver Control register */ | ||
806 | #define SPICTL_EN 0x00000001 | ||
807 | #define SPICTL_I24 0x00000002 | ||
808 | #define SPICTL_IB 0x00000004 | ||
809 | #define SPICTL_SM 0x00000008 | ||
810 | #define SPICTL_VM 0x00000010 | ||
811 | |||
812 | /* DAIO manager register dirty flags */ | ||
813 | union daio_mgr_dirty { | ||
814 | struct { | ||
815 | u32 i2soctl:4; | ||
816 | u32 i2sictl:4; | ||
817 | u32 spoctl:4; | ||
818 | u32 spictl:4; | ||
819 | u32 daoimap:1; | ||
820 | u32 rsv:15; | ||
821 | } bf; | ||
822 | u32 data; | ||
823 | }; | ||
824 | |||
825 | /* DAIO manager control block */ | ||
826 | struct daio_mgr_ctrl_blk { | ||
827 | unsigned int i2sctl; | ||
828 | unsigned int spoctl; | ||
829 | unsigned int spictl; | ||
830 | struct daoimap daoimap; | ||
831 | union daio_mgr_dirty dirty; | ||
832 | }; | ||
833 | |||
834 | static int dai_srt_set_srcr(void *blk, unsigned int src) | ||
835 | { | ||
836 | struct dai_ctrl_blk *ctl = blk; | ||
837 | |||
838 | set_field(&ctl->srtctl, SRTCTL_SRCR, src); | ||
839 | ctl->dirty.bf.srtctl = 1; | ||
840 | return 0; | ||
841 | } | ||
842 | |||
843 | static int dai_srt_set_srcl(void *blk, unsigned int src) | ||
844 | { | ||
845 | struct dai_ctrl_blk *ctl = blk; | ||
846 | |||
847 | set_field(&ctl->srtctl, SRTCTL_SRCL, src); | ||
848 | ctl->dirty.bf.srtctl = 1; | ||
849 | return 0; | ||
850 | } | ||
851 | |||
852 | static int dai_srt_set_rsr(void *blk, unsigned int rsr) | ||
853 | { | ||
854 | struct dai_ctrl_blk *ctl = blk; | ||
855 | |||
856 | set_field(&ctl->srtctl, SRTCTL_RSR, rsr); | ||
857 | ctl->dirty.bf.srtctl = 1; | ||
858 | return 0; | ||
859 | } | ||
860 | |||
861 | static int dai_srt_set_drat(void *blk, unsigned int drat) | ||
862 | { | ||
863 | struct dai_ctrl_blk *ctl = blk; | ||
864 | |||
865 | set_field(&ctl->srtctl, SRTCTL_DRAT, drat); | ||
866 | ctl->dirty.bf.srtctl = 1; | ||
867 | return 0; | ||
868 | } | ||
869 | |||
870 | static int dai_srt_set_ec(void *blk, unsigned int ec) | ||
871 | { | ||
872 | struct dai_ctrl_blk *ctl = blk; | ||
873 | |||
874 | set_field(&ctl->srtctl, SRTCTL_EC, ec ? 1 : 0); | ||
875 | ctl->dirty.bf.srtctl = 1; | ||
876 | return 0; | ||
877 | } | ||
878 | |||
879 | static int dai_srt_set_et(void *blk, unsigned int et) | ||
880 | { | ||
881 | struct dai_ctrl_blk *ctl = blk; | ||
882 | |||
883 | set_field(&ctl->srtctl, SRTCTL_ET, et ? 1 : 0); | ||
884 | ctl->dirty.bf.srtctl = 1; | ||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk) | ||
889 | { | ||
890 | struct dai_ctrl_blk *ctl = blk; | ||
891 | |||
892 | if (ctl->dirty.bf.srtctl) { | ||
893 | if (idx < 4) { | ||
894 | /* S/PDIF SRTs */ | ||
895 | hw_write_20kx(hw, SRTSCTL+0x4*idx, ctl->srtctl); | ||
896 | } else { | ||
897 | /* I2S SRT */ | ||
898 | hw_write_20kx(hw, SRTICTL, ctl->srtctl); | ||
899 | } | ||
900 | ctl->dirty.bf.srtctl = 0; | ||
901 | } | ||
902 | |||
903 | return 0; | ||
904 | } | ||
905 | |||
906 | static int dai_get_ctrl_blk(void **rblk) | ||
907 | { | ||
908 | struct dai_ctrl_blk *blk; | ||
909 | |||
910 | *rblk = NULL; | ||
911 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
912 | if (NULL == blk) | ||
913 | return -ENOMEM; | ||
914 | |||
915 | *rblk = blk; | ||
916 | |||
917 | return 0; | ||
918 | } | ||
919 | |||
920 | static int dai_put_ctrl_blk(void *blk) | ||
921 | { | ||
922 | kfree((struct dai_ctrl_blk *)blk); | ||
923 | |||
924 | return 0; | ||
925 | } | ||
926 | |||
927 | static int dao_set_spos(void *blk, unsigned int spos) | ||
928 | { | ||
929 | ((struct dao_ctrl_blk *)blk)->spos = spos; | ||
930 | ((struct dao_ctrl_blk *)blk)->dirty.bf.spos = 1; | ||
931 | return 0; | ||
932 | } | ||
933 | |||
934 | static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk) | ||
935 | { | ||
936 | struct dao_ctrl_blk *ctl = blk; | ||
937 | |||
938 | if (ctl->dirty.bf.spos) { | ||
939 | if (idx < 4) { | ||
940 | /* S/PDIF SPOSx */ | ||
941 | hw_write_20kx(hw, SPOS+0x4*idx, ctl->spos); | ||
942 | } | ||
943 | ctl->dirty.bf.spos = 0; | ||
944 | } | ||
945 | |||
946 | return 0; | ||
947 | } | ||
948 | |||
949 | static int dao_get_spos(void *blk, unsigned int *spos) | ||
950 | { | ||
951 | *spos = ((struct dao_ctrl_blk *)blk)->spos; | ||
952 | return 0; | ||
953 | } | ||
954 | |||
955 | static int dao_get_ctrl_blk(void **rblk) | ||
956 | { | ||
957 | struct dao_ctrl_blk *blk; | ||
958 | |||
959 | *rblk = NULL; | ||
960 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
961 | if (NULL == blk) | ||
962 | return -ENOMEM; | ||
963 | |||
964 | *rblk = blk; | ||
965 | |||
966 | return 0; | ||
967 | } | ||
968 | |||
969 | static int dao_put_ctrl_blk(void *blk) | ||
970 | { | ||
971 | kfree((struct dao_ctrl_blk *)blk); | ||
972 | |||
973 | return 0; | ||
974 | } | ||
975 | |||
976 | static int daio_mgr_enb_dai(void *blk, unsigned int idx) | ||
977 | { | ||
978 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
979 | |||
980 | if (idx < 4) { | ||
981 | /* S/PDIF input */ | ||
982 | set_field(&ctl->spictl, SPICTL_EN << (idx*8), 1); | ||
983 | ctl->dirty.bf.spictl |= (0x1 << idx); | ||
984 | } else { | ||
985 | /* I2S input */ | ||
986 | idx %= 4; | ||
987 | set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 1); | ||
988 | ctl->dirty.bf.i2sictl |= (0x1 << idx); | ||
989 | } | ||
990 | return 0; | ||
991 | } | ||
992 | |||
993 | static int daio_mgr_dsb_dai(void *blk, unsigned int idx) | ||
994 | { | ||
995 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
996 | |||
997 | if (idx < 4) { | ||
998 | /* S/PDIF input */ | ||
999 | set_field(&ctl->spictl, SPICTL_EN << (idx*8), 0); | ||
1000 | ctl->dirty.bf.spictl |= (0x1 << idx); | ||
1001 | } else { | ||
1002 | /* I2S input */ | ||
1003 | idx %= 4; | ||
1004 | set_field(&ctl->i2sctl, I2SCTL_EI << (idx*8), 0); | ||
1005 | ctl->dirty.bf.i2sictl |= (0x1 << idx); | ||
1006 | } | ||
1007 | return 0; | ||
1008 | } | ||
1009 | |||
1010 | static int daio_mgr_enb_dao(void *blk, unsigned int idx) | ||
1011 | { | ||
1012 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1013 | |||
1014 | if (idx < 4) { | ||
1015 | /* S/PDIF output */ | ||
1016 | set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 1); | ||
1017 | ctl->dirty.bf.spoctl |= (0x1 << idx); | ||
1018 | } else { | ||
1019 | /* I2S output */ | ||
1020 | idx %= 4; | ||
1021 | set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 1); | ||
1022 | ctl->dirty.bf.i2soctl |= (0x1 << idx); | ||
1023 | } | ||
1024 | return 0; | ||
1025 | } | ||
1026 | |||
1027 | static int daio_mgr_dsb_dao(void *blk, unsigned int idx) | ||
1028 | { | ||
1029 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1030 | |||
1031 | if (idx < 4) { | ||
1032 | /* S/PDIF output */ | ||
1033 | set_field(&ctl->spoctl, SPOCTL_OE << (idx*8), 0); | ||
1034 | ctl->dirty.bf.spoctl |= (0x1 << idx); | ||
1035 | } else { | ||
1036 | /* I2S output */ | ||
1037 | idx %= 4; | ||
1038 | set_field(&ctl->i2sctl, I2SCTL_EA << (idx*8), 0); | ||
1039 | ctl->dirty.bf.i2soctl |= (0x1 << idx); | ||
1040 | } | ||
1041 | return 0; | ||
1042 | } | ||
1043 | |||
1044 | static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) | ||
1045 | { | ||
1046 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1047 | |||
1048 | if (idx < 4) { | ||
1049 | /* S/PDIF output */ | ||
1050 | switch ((conf & 0x7)) { | ||
1051 | case 0: | ||
1052 | set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 3); | ||
1053 | break; /* CDIF */ | ||
1054 | case 1: | ||
1055 | set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 0); | ||
1056 | break; | ||
1057 | case 2: | ||
1058 | set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 1); | ||
1059 | break; | ||
1060 | case 4: | ||
1061 | set_field(&ctl->spoctl, SPOCTL_SR << (idx*8), 2); | ||
1062 | break; | ||
1063 | default: | ||
1064 | break; | ||
1065 | } | ||
1066 | set_field(&ctl->spoctl, SPOCTL_LIV << (idx*8), | ||
1067 | (conf >> 4) & 0x1); /* Non-audio */ | ||
1068 | set_field(&ctl->spoctl, SPOCTL_RIV << (idx*8), | ||
1069 | (conf >> 4) & 0x1); /* Non-audio */ | ||
1070 | set_field(&ctl->spoctl, SPOCTL_OS << (idx*8), | ||
1071 | ((conf >> 3) & 0x1) ? 2 : 2); /* Raw */ | ||
1072 | |||
1073 | ctl->dirty.bf.spoctl |= (0x1 << idx); | ||
1074 | } else { | ||
1075 | /* I2S output */ | ||
1076 | /*idx %= 4; */ | ||
1077 | } | ||
1078 | return 0; | ||
1079 | } | ||
1080 | |||
1081 | static int daio_mgr_set_imaparc(void *blk, unsigned int slot) | ||
1082 | { | ||
1083 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1084 | |||
1085 | set_field(&ctl->daoimap.aim, AIM_ARC, slot); | ||
1086 | ctl->dirty.bf.daoimap = 1; | ||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | static int daio_mgr_set_imapnxt(void *blk, unsigned int next) | ||
1091 | { | ||
1092 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1093 | |||
1094 | set_field(&ctl->daoimap.aim, AIM_NXT, next); | ||
1095 | ctl->dirty.bf.daoimap = 1; | ||
1096 | return 0; | ||
1097 | } | ||
1098 | |||
1099 | static int daio_mgr_set_imapaddr(void *blk, unsigned int addr) | ||
1100 | { | ||
1101 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1102 | |||
1103 | ctl->daoimap.idx = addr; | ||
1104 | ctl->dirty.bf.daoimap = 1; | ||
1105 | return 0; | ||
1106 | } | ||
1107 | |||
1108 | static int daio_mgr_commit_write(struct hw *hw, void *blk) | ||
1109 | { | ||
1110 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1111 | int i; | ||
1112 | |||
1113 | if (ctl->dirty.bf.i2sictl || ctl->dirty.bf.i2soctl) { | ||
1114 | for (i = 0; i < 4; i++) { | ||
1115 | if ((ctl->dirty.bf.i2sictl & (0x1 << i))) | ||
1116 | ctl->dirty.bf.i2sictl &= ~(0x1 << i); | ||
1117 | |||
1118 | if ((ctl->dirty.bf.i2soctl & (0x1 << i))) | ||
1119 | ctl->dirty.bf.i2soctl &= ~(0x1 << i); | ||
1120 | } | ||
1121 | hw_write_20kx(hw, I2SCTL, ctl->i2sctl); | ||
1122 | mdelay(1); | ||
1123 | } | ||
1124 | if (ctl->dirty.bf.spoctl) { | ||
1125 | for (i = 0; i < 4; i++) { | ||
1126 | if ((ctl->dirty.bf.spoctl & (0x1 << i))) | ||
1127 | ctl->dirty.bf.spoctl &= ~(0x1 << i); | ||
1128 | } | ||
1129 | hw_write_20kx(hw, SPOCTL, ctl->spoctl); | ||
1130 | mdelay(1); | ||
1131 | } | ||
1132 | if (ctl->dirty.bf.spictl) { | ||
1133 | for (i = 0; i < 4; i++) { | ||
1134 | if ((ctl->dirty.bf.spictl & (0x1 << i))) | ||
1135 | ctl->dirty.bf.spictl &= ~(0x1 << i); | ||
1136 | } | ||
1137 | hw_write_20kx(hw, SPICTL, ctl->spictl); | ||
1138 | mdelay(1); | ||
1139 | } | ||
1140 | if (ctl->dirty.bf.daoimap) { | ||
1141 | hw_write_20kx(hw, DAOIMAP+ctl->daoimap.idx*4, | ||
1142 | ctl->daoimap.aim); | ||
1143 | ctl->dirty.bf.daoimap = 0; | ||
1144 | } | ||
1145 | |||
1146 | return 0; | ||
1147 | } | ||
1148 | |||
1149 | static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) | ||
1150 | { | ||
1151 | struct daio_mgr_ctrl_blk *blk; | ||
1152 | |||
1153 | *rblk = NULL; | ||
1154 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
1155 | if (NULL == blk) | ||
1156 | return -ENOMEM; | ||
1157 | |||
1158 | blk->i2sctl = hw_read_20kx(hw, I2SCTL); | ||
1159 | blk->spoctl = hw_read_20kx(hw, SPOCTL); | ||
1160 | blk->spictl = hw_read_20kx(hw, SPICTL); | ||
1161 | |||
1162 | *rblk = blk; | ||
1163 | |||
1164 | return 0; | ||
1165 | } | ||
1166 | |||
1167 | static int daio_mgr_put_ctrl_blk(void *blk) | ||
1168 | { | ||
1169 | kfree((struct daio_mgr_ctrl_blk *)blk); | ||
1170 | |||
1171 | return 0; | ||
1172 | } | ||
1173 | |||
1174 | /* Timer interrupt */ | ||
1175 | static int set_timer_irq(struct hw *hw, int enable) | ||
1176 | { | ||
1177 | hw_write_20kx(hw, GIE, enable ? IT_INT : 0); | ||
1178 | return 0; | ||
1179 | } | ||
1180 | |||
1181 | static int set_timer_tick(struct hw *hw, unsigned int ticks) | ||
1182 | { | ||
1183 | if (ticks) | ||
1184 | ticks |= TIMR_IE | TIMR_IP; | ||
1185 | hw_write_20kx(hw, TIMR, ticks); | ||
1186 | return 0; | ||
1187 | } | ||
1188 | |||
1189 | static unsigned int get_wc(struct hw *hw) | ||
1190 | { | ||
1191 | return hw_read_20kx(hw, WC); | ||
1192 | } | ||
1193 | |||
1194 | /* Card hardware initialization block */ | ||
1195 | struct dac_conf { | ||
1196 | unsigned int msr; /* master sample rate in rsrs */ | ||
1197 | }; | ||
1198 | |||
1199 | struct adc_conf { | ||
1200 | unsigned int msr; /* master sample rate in rsrs */ | ||
1201 | unsigned char input; /* the input source of ADC */ | ||
1202 | unsigned char mic20db; /* boost mic by 20db if input is microphone */ | ||
1203 | }; | ||
1204 | |||
1205 | struct daio_conf { | ||
1206 | unsigned int msr; /* master sample rate in rsrs */ | ||
1207 | }; | ||
1208 | |||
1209 | struct trn_conf { | ||
1210 | unsigned long vm_pgt_phys; | ||
1211 | }; | ||
1212 | |||
1213 | static int hw_daio_init(struct hw *hw, const struct daio_conf *info) | ||
1214 | { | ||
1215 | u32 i2sorg; | ||
1216 | u32 spdorg; | ||
1217 | |||
1218 | /* Read I2S CTL. Keep original value. */ | ||
1219 | /*i2sorg = hw_read_20kx(hw, I2SCTL);*/ | ||
1220 | i2sorg = 0x94040404; /* enable all audio out and I2S-D input */ | ||
1221 | /* Program I2S with proper master sample rate and enable | ||
1222 | * the correct I2S channel. */ | ||
1223 | i2sorg &= 0xfffffffc; | ||
1224 | |||
1225 | /* Enable S/PDIF-out-A in fixed 24-bit data | ||
1226 | * format and default to 48kHz. */ | ||
1227 | /* Disable all before doing any changes. */ | ||
1228 | hw_write_20kx(hw, SPOCTL, 0x0); | ||
1229 | spdorg = 0x05; | ||
1230 | |||
1231 | switch (info->msr) { | ||
1232 | case 1: | ||
1233 | i2sorg |= 1; | ||
1234 | spdorg |= (0x0 << 6); | ||
1235 | break; | ||
1236 | case 2: | ||
1237 | i2sorg |= 2; | ||
1238 | spdorg |= (0x1 << 6); | ||
1239 | break; | ||
1240 | case 4: | ||
1241 | i2sorg |= 3; | ||
1242 | spdorg |= (0x2 << 6); | ||
1243 | break; | ||
1244 | default: | ||
1245 | i2sorg |= 1; | ||
1246 | break; | ||
1247 | } | ||
1248 | |||
1249 | hw_write_20kx(hw, I2SCTL, i2sorg); | ||
1250 | hw_write_20kx(hw, SPOCTL, spdorg); | ||
1251 | |||
1252 | /* Enable S/PDIF-in-A in fixed 24-bit data format. */ | ||
1253 | /* Disable all before doing any changes. */ | ||
1254 | hw_write_20kx(hw, SPICTL, 0x0); | ||
1255 | mdelay(1); | ||
1256 | spdorg = 0x0a0a0a0a; | ||
1257 | hw_write_20kx(hw, SPICTL, spdorg); | ||
1258 | mdelay(1); | ||
1259 | |||
1260 | return 0; | ||
1261 | } | ||
1262 | |||
1263 | /* TRANSPORT operations */ | ||
1264 | static int hw_trn_init(struct hw *hw, const struct trn_conf *info) | ||
1265 | { | ||
1266 | u32 trnctl; | ||
1267 | u32 ptp_phys_low, ptp_phys_high; | ||
1268 | |||
1269 | /* Set up device page table */ | ||
1270 | if ((~0UL) == info->vm_pgt_phys) { | ||
1271 | printk(KERN_ERR "Wrong device page table page address!\n"); | ||
1272 | return -1; | ||
1273 | } | ||
1274 | |||
1275 | trnctl = 0x13; /* 32-bit, 4k-size page */ | ||
1276 | ptp_phys_low = (u32)info->vm_pgt_phys; | ||
1277 | ptp_phys_high = upper_32_bits(info->vm_pgt_phys); | ||
1278 | if (sizeof(void *) == 8) /* 64bit address */ | ||
1279 | trnctl |= (1 << 2); | ||
1280 | #if 0 /* Only 4k h/w pages for simplicitiy */ | ||
1281 | #if PAGE_SIZE == 8192 | ||
1282 | trnctl |= (1<<5); | ||
1283 | #endif | ||
1284 | #endif | ||
1285 | hw_write_20kx(hw, PTPALX, ptp_phys_low); | ||
1286 | hw_write_20kx(hw, PTPAHX, ptp_phys_high); | ||
1287 | hw_write_20kx(hw, TRNCTL, trnctl); | ||
1288 | hw_write_20kx(hw, TRNIS, 0x200c01); /* realy needed? */ | ||
1289 | |||
1290 | return 0; | ||
1291 | } | ||
1292 | |||
1293 | /* Card initialization */ | ||
1294 | #define GCTL_EAC 0x00000001 | ||
1295 | #define GCTL_EAI 0x00000002 | ||
1296 | #define GCTL_BEP 0x00000004 | ||
1297 | #define GCTL_BES 0x00000008 | ||
1298 | #define GCTL_DSP 0x00000010 | ||
1299 | #define GCTL_DBP 0x00000020 | ||
1300 | #define GCTL_ABP 0x00000040 | ||
1301 | #define GCTL_TBP 0x00000080 | ||
1302 | #define GCTL_SBP 0x00000100 | ||
1303 | #define GCTL_FBP 0x00000200 | ||
1304 | #define GCTL_XA 0x00000400 | ||
1305 | #define GCTL_ET 0x00000800 | ||
1306 | #define GCTL_PR 0x00001000 | ||
1307 | #define GCTL_MRL 0x00002000 | ||
1308 | #define GCTL_SDE 0x00004000 | ||
1309 | #define GCTL_SDI 0x00008000 | ||
1310 | #define GCTL_SM 0x00010000 | ||
1311 | #define GCTL_SR 0x00020000 | ||
1312 | #define GCTL_SD 0x00040000 | ||
1313 | #define GCTL_SE 0x00080000 | ||
1314 | #define GCTL_AID 0x00100000 | ||
1315 | |||
1316 | static int hw_pll_init(struct hw *hw, unsigned int rsr) | ||
1317 | { | ||
1318 | unsigned int pllctl; | ||
1319 | int i; | ||
1320 | |||
1321 | pllctl = (48000 == rsr) ? 0x1480a001 : 0x1480a731; | ||
1322 | for (i = 0; i < 3; i++) { | ||
1323 | if (hw_read_20kx(hw, PLLCTL) == pllctl) | ||
1324 | break; | ||
1325 | |||
1326 | hw_write_20kx(hw, PLLCTL, pllctl); | ||
1327 | mdelay(40); | ||
1328 | } | ||
1329 | if (i >= 3) { | ||
1330 | printk(KERN_ALERT "PLL initialization failed!!!\n"); | ||
1331 | return -EBUSY; | ||
1332 | } | ||
1333 | |||
1334 | return 0; | ||
1335 | } | ||
1336 | |||
1337 | static int hw_auto_init(struct hw *hw) | ||
1338 | { | ||
1339 | unsigned int gctl; | ||
1340 | int i; | ||
1341 | |||
1342 | gctl = hw_read_20kx(hw, GCTL); | ||
1343 | set_field(&gctl, GCTL_EAI, 0); | ||
1344 | hw_write_20kx(hw, GCTL, gctl); | ||
1345 | set_field(&gctl, GCTL_EAI, 1); | ||
1346 | hw_write_20kx(hw, GCTL, gctl); | ||
1347 | mdelay(10); | ||
1348 | for (i = 0; i < 400000; i++) { | ||
1349 | gctl = hw_read_20kx(hw, GCTL); | ||
1350 | if (get_field(gctl, GCTL_AID)) | ||
1351 | break; | ||
1352 | } | ||
1353 | if (!get_field(gctl, GCTL_AID)) { | ||
1354 | printk(KERN_ALERT "Card Auto-init failed!!!\n"); | ||
1355 | return -EBUSY; | ||
1356 | } | ||
1357 | |||
1358 | return 0; | ||
1359 | } | ||
1360 | |||
1361 | static int i2c_unlock(struct hw *hw) | ||
1362 | { | ||
1363 | if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) | ||
1364 | return 0; | ||
1365 | |||
1366 | hw_write_pci(hw, 0xcc, 0x8c); | ||
1367 | hw_write_pci(hw, 0xcc, 0x0e); | ||
1368 | if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) | ||
1369 | return 0; | ||
1370 | |||
1371 | hw_write_pci(hw, 0xcc, 0xee); | ||
1372 | hw_write_pci(hw, 0xcc, 0xaa); | ||
1373 | if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) | ||
1374 | return 0; | ||
1375 | |||
1376 | return -1; | ||
1377 | } | ||
1378 | |||
1379 | static void i2c_lock(struct hw *hw) | ||
1380 | { | ||
1381 | if ((hw_read_pci(hw, 0xcc) & 0xff) == 0xaa) | ||
1382 | hw_write_pci(hw, 0xcc, 0x00); | ||
1383 | } | ||
1384 | |||
1385 | static void i2c_write(struct hw *hw, u32 device, u32 addr, u32 data) | ||
1386 | { | ||
1387 | unsigned int ret; | ||
1388 | |||
1389 | do { | ||
1390 | ret = hw_read_pci(hw, 0xEC); | ||
1391 | } while (!(ret & 0x800000)); | ||
1392 | hw_write_pci(hw, 0xE0, device); | ||
1393 | hw_write_pci(hw, 0xE4, (data << 8) | (addr & 0xff)); | ||
1394 | } | ||
1395 | |||
1396 | /* DAC operations */ | ||
1397 | |||
1398 | static int hw_reset_dac(struct hw *hw) | ||
1399 | { | ||
1400 | u32 i; | ||
1401 | u16 gpioorg; | ||
1402 | unsigned int ret; | ||
1403 | |||
1404 | if (i2c_unlock(hw)) | ||
1405 | return -1; | ||
1406 | |||
1407 | do { | ||
1408 | ret = hw_read_pci(hw, 0xEC); | ||
1409 | } while (!(ret & 0x800000)); | ||
1410 | hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ | ||
1411 | |||
1412 | /* To be effective, need to reset the DAC twice. */ | ||
1413 | for (i = 0; i < 2; i++) { | ||
1414 | /* set gpio */ | ||
1415 | mdelay(100); | ||
1416 | gpioorg = (u16)hw_read_20kx(hw, GPIO); | ||
1417 | gpioorg &= 0xfffd; | ||
1418 | hw_write_20kx(hw, GPIO, gpioorg); | ||
1419 | mdelay(1); | ||
1420 | hw_write_20kx(hw, GPIO, gpioorg | 0x2); | ||
1421 | } | ||
1422 | |||
1423 | i2c_write(hw, 0x00180080, 0x01, 0x80); | ||
1424 | i2c_write(hw, 0x00180080, 0x02, 0x10); | ||
1425 | |||
1426 | i2c_lock(hw); | ||
1427 | |||
1428 | return 0; | ||
1429 | } | ||
1430 | |||
1431 | static int hw_dac_init(struct hw *hw, const struct dac_conf *info) | ||
1432 | { | ||
1433 | u32 data; | ||
1434 | u16 gpioorg; | ||
1435 | unsigned int ret; | ||
1436 | |||
1437 | if (hw->model == CTSB055X) { | ||
1438 | /* SB055x, unmute outputs */ | ||
1439 | gpioorg = (u16)hw_read_20kx(hw, GPIO); | ||
1440 | gpioorg &= 0xffbf; /* set GPIO6 to low */ | ||
1441 | gpioorg |= 2; /* set GPIO1 to high */ | ||
1442 | hw_write_20kx(hw, GPIO, gpioorg); | ||
1443 | return 0; | ||
1444 | } | ||
1445 | |||
1446 | /* mute outputs */ | ||
1447 | gpioorg = (u16)hw_read_20kx(hw, GPIO); | ||
1448 | gpioorg &= 0xffbf; | ||
1449 | hw_write_20kx(hw, GPIO, gpioorg); | ||
1450 | |||
1451 | hw_reset_dac(hw); | ||
1452 | |||
1453 | if (i2c_unlock(hw)) | ||
1454 | return -1; | ||
1455 | |||
1456 | hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ | ||
1457 | do { | ||
1458 | ret = hw_read_pci(hw, 0xEC); | ||
1459 | } while (!(ret & 0x800000)); | ||
1460 | |||
1461 | switch (info->msr) { | ||
1462 | case 1: | ||
1463 | data = 0x24; | ||
1464 | break; | ||
1465 | case 2: | ||
1466 | data = 0x25; | ||
1467 | break; | ||
1468 | case 4: | ||
1469 | data = 0x26; | ||
1470 | break; | ||
1471 | default: | ||
1472 | data = 0x24; | ||
1473 | break; | ||
1474 | } | ||
1475 | |||
1476 | i2c_write(hw, 0x00180080, 0x06, data); | ||
1477 | i2c_write(hw, 0x00180080, 0x09, data); | ||
1478 | i2c_write(hw, 0x00180080, 0x0c, data); | ||
1479 | i2c_write(hw, 0x00180080, 0x0f, data); | ||
1480 | |||
1481 | i2c_lock(hw); | ||
1482 | |||
1483 | /* unmute outputs */ | ||
1484 | gpioorg = (u16)hw_read_20kx(hw, GPIO); | ||
1485 | gpioorg = gpioorg | 0x40; | ||
1486 | hw_write_20kx(hw, GPIO, gpioorg); | ||
1487 | |||
1488 | return 0; | ||
1489 | } | ||
1490 | |||
1491 | /* ADC operations */ | ||
1492 | |||
1493 | static int is_adc_input_selected_SB055x(struct hw *hw, enum ADCSRC type) | ||
1494 | { | ||
1495 | return 0; | ||
1496 | } | ||
1497 | |||
1498 | static int is_adc_input_selected_SBx(struct hw *hw, enum ADCSRC type) | ||
1499 | { | ||
1500 | u32 data; | ||
1501 | |||
1502 | data = hw_read_20kx(hw, GPIO); | ||
1503 | switch (type) { | ||
1504 | case ADC_MICIN: | ||
1505 | data = ((data & (0x1<<7)) && (data & (0x1<<8))); | ||
1506 | break; | ||
1507 | case ADC_LINEIN: | ||
1508 | data = (!(data & (0x1<<7)) && (data & (0x1<<8))); | ||
1509 | break; | ||
1510 | case ADC_NONE: /* Digital I/O */ | ||
1511 | data = (!(data & (0x1<<8))); | ||
1512 | break; | ||
1513 | default: | ||
1514 | data = 0; | ||
1515 | } | ||
1516 | return data; | ||
1517 | } | ||
1518 | |||
1519 | static int is_adc_input_selected_hendrix(struct hw *hw, enum ADCSRC type) | ||
1520 | { | ||
1521 | u32 data; | ||
1522 | |||
1523 | data = hw_read_20kx(hw, GPIO); | ||
1524 | switch (type) { | ||
1525 | case ADC_MICIN: | ||
1526 | data = (data & (0x1 << 7)) ? 1 : 0; | ||
1527 | break; | ||
1528 | case ADC_LINEIN: | ||
1529 | data = (data & (0x1 << 7)) ? 0 : 1; | ||
1530 | break; | ||
1531 | default: | ||
1532 | data = 0; | ||
1533 | } | ||
1534 | return data; | ||
1535 | } | ||
1536 | |||
1537 | static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) | ||
1538 | { | ||
1539 | switch (hw->model) { | ||
1540 | case CTSB055X: | ||
1541 | return is_adc_input_selected_SB055x(hw, type); | ||
1542 | case CTSB073X: | ||
1543 | return is_adc_input_selected_hendrix(hw, type); | ||
1544 | case CTUAA: | ||
1545 | return is_adc_input_selected_hendrix(hw, type); | ||
1546 | default: | ||
1547 | return is_adc_input_selected_SBx(hw, type); | ||
1548 | } | ||
1549 | } | ||
1550 | |||
1551 | static int | ||
1552 | adc_input_select_SB055x(struct hw *hw, enum ADCSRC type, unsigned char boost) | ||
1553 | { | ||
1554 | u32 data; | ||
1555 | |||
1556 | /* | ||
1557 | * check and set the following GPIO bits accordingly | ||
1558 | * ADC_Gain = GPIO2 | ||
1559 | * DRM_off = GPIO3 | ||
1560 | * Mic_Pwr_on = GPIO7 | ||
1561 | * Digital_IO_Sel = GPIO8 | ||
1562 | * Mic_Sw = GPIO9 | ||
1563 | * Aux/MicLine_Sw = GPIO12 | ||
1564 | */ | ||
1565 | data = hw_read_20kx(hw, GPIO); | ||
1566 | data &= 0xec73; | ||
1567 | switch (type) { | ||
1568 | case ADC_MICIN: | ||
1569 | data |= (0x1<<7) | (0x1<<8) | (0x1<<9) ; | ||
1570 | data |= boost ? (0x1<<2) : 0; | ||
1571 | break; | ||
1572 | case ADC_LINEIN: | ||
1573 | data |= (0x1<<8); | ||
1574 | break; | ||
1575 | case ADC_AUX: | ||
1576 | data |= (0x1<<8) | (0x1<<12); | ||
1577 | break; | ||
1578 | case ADC_NONE: | ||
1579 | data |= (0x1<<12); /* set to digital */ | ||
1580 | break; | ||
1581 | default: | ||
1582 | return -1; | ||
1583 | } | ||
1584 | |||
1585 | hw_write_20kx(hw, GPIO, data); | ||
1586 | |||
1587 | return 0; | ||
1588 | } | ||
1589 | |||
1590 | |||
1591 | static int | ||
1592 | adc_input_select_SBx(struct hw *hw, enum ADCSRC type, unsigned char boost) | ||
1593 | { | ||
1594 | u32 data; | ||
1595 | u32 i2c_data; | ||
1596 | unsigned int ret; | ||
1597 | |||
1598 | if (i2c_unlock(hw)) | ||
1599 | return -1; | ||
1600 | |||
1601 | do { | ||
1602 | ret = hw_read_pci(hw, 0xEC); | ||
1603 | } while (!(ret & 0x800000)); /* i2c ready poll */ | ||
1604 | /* set i2c access mode as Direct Control */ | ||
1605 | hw_write_pci(hw, 0xEC, 0x05); | ||
1606 | |||
1607 | data = hw_read_20kx(hw, GPIO); | ||
1608 | switch (type) { | ||
1609 | case ADC_MICIN: | ||
1610 | data |= ((0x1 << 7) | (0x1 << 8)); | ||
1611 | i2c_data = 0x1; /* Mic-in */ | ||
1612 | break; | ||
1613 | case ADC_LINEIN: | ||
1614 | data &= ~(0x1 << 7); | ||
1615 | data |= (0x1 << 8); | ||
1616 | i2c_data = 0x2; /* Line-in */ | ||
1617 | break; | ||
1618 | case ADC_NONE: | ||
1619 | data &= ~(0x1 << 8); | ||
1620 | i2c_data = 0x0; /* set to Digital */ | ||
1621 | break; | ||
1622 | default: | ||
1623 | i2c_lock(hw); | ||
1624 | return -1; | ||
1625 | } | ||
1626 | hw_write_20kx(hw, GPIO, data); | ||
1627 | i2c_write(hw, 0x001a0080, 0x2a, i2c_data); | ||
1628 | if (boost) { | ||
1629 | i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */ | ||
1630 | i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */ | ||
1631 | } else { | ||
1632 | i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */ | ||
1633 | i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */ | ||
1634 | } | ||
1635 | |||
1636 | i2c_lock(hw); | ||
1637 | |||
1638 | return 0; | ||
1639 | } | ||
1640 | |||
1641 | static int | ||
1642 | adc_input_select_hendrix(struct hw *hw, enum ADCSRC type, unsigned char boost) | ||
1643 | { | ||
1644 | u32 data; | ||
1645 | u32 i2c_data; | ||
1646 | unsigned int ret; | ||
1647 | |||
1648 | if (i2c_unlock(hw)) | ||
1649 | return -1; | ||
1650 | |||
1651 | do { | ||
1652 | ret = hw_read_pci(hw, 0xEC); | ||
1653 | } while (!(ret & 0x800000)); /* i2c ready poll */ | ||
1654 | /* set i2c access mode as Direct Control */ | ||
1655 | hw_write_pci(hw, 0xEC, 0x05); | ||
1656 | |||
1657 | data = hw_read_20kx(hw, GPIO); | ||
1658 | switch (type) { | ||
1659 | case ADC_MICIN: | ||
1660 | data |= (0x1 << 7); | ||
1661 | i2c_data = 0x1; /* Mic-in */ | ||
1662 | break; | ||
1663 | case ADC_LINEIN: | ||
1664 | data &= ~(0x1 << 7); | ||
1665 | i2c_data = 0x2; /* Line-in */ | ||
1666 | break; | ||
1667 | default: | ||
1668 | i2c_lock(hw); | ||
1669 | return -1; | ||
1670 | } | ||
1671 | hw_write_20kx(hw, GPIO, data); | ||
1672 | i2c_write(hw, 0x001a0080, 0x2a, i2c_data); | ||
1673 | if (boost) { | ||
1674 | i2c_write(hw, 0x001a0080, 0x1c, 0xe7); /* +12dB boost */ | ||
1675 | i2c_write(hw, 0x001a0080, 0x1e, 0xe7); /* +12dB boost */ | ||
1676 | } else { | ||
1677 | i2c_write(hw, 0x001a0080, 0x1c, 0xcf); /* No boost */ | ||
1678 | i2c_write(hw, 0x001a0080, 0x1e, 0xcf); /* No boost */ | ||
1679 | } | ||
1680 | |||
1681 | i2c_lock(hw); | ||
1682 | |||
1683 | return 0; | ||
1684 | } | ||
1685 | |||
1686 | static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) | ||
1687 | { | ||
1688 | int state = type == ADC_MICIN; | ||
1689 | |||
1690 | switch (hw->model) { | ||
1691 | case CTSB055X: | ||
1692 | return adc_input_select_SB055x(hw, type, state); | ||
1693 | case CTSB073X: | ||
1694 | return adc_input_select_hendrix(hw, type, state); | ||
1695 | case CTUAA: | ||
1696 | return adc_input_select_hendrix(hw, type, state); | ||
1697 | default: | ||
1698 | return adc_input_select_SBx(hw, type, state); | ||
1699 | } | ||
1700 | } | ||
1701 | |||
1702 | static int adc_init_SB055x(struct hw *hw, int input, int mic20db) | ||
1703 | { | ||
1704 | return adc_input_select_SB055x(hw, input, mic20db); | ||
1705 | } | ||
1706 | |||
1707 | static int adc_init_SBx(struct hw *hw, int input, int mic20db) | ||
1708 | { | ||
1709 | u16 gpioorg; | ||
1710 | u16 input_source; | ||
1711 | u32 adcdata; | ||
1712 | unsigned int ret; | ||
1713 | |||
1714 | input_source = 0x100; /* default to analog */ | ||
1715 | switch (input) { | ||
1716 | case ADC_MICIN: | ||
1717 | adcdata = 0x1; | ||
1718 | input_source = 0x180; /* set GPIO7 to select Mic */ | ||
1719 | break; | ||
1720 | case ADC_LINEIN: | ||
1721 | adcdata = 0x2; | ||
1722 | break; | ||
1723 | case ADC_VIDEO: | ||
1724 | adcdata = 0x4; | ||
1725 | break; | ||
1726 | case ADC_AUX: | ||
1727 | adcdata = 0x8; | ||
1728 | break; | ||
1729 | case ADC_NONE: | ||
1730 | adcdata = 0x0; | ||
1731 | input_source = 0x0; /* set to Digital */ | ||
1732 | break; | ||
1733 | default: | ||
1734 | adcdata = 0x0; | ||
1735 | break; | ||
1736 | } | ||
1737 | |||
1738 | if (i2c_unlock(hw)) | ||
1739 | return -1; | ||
1740 | |||
1741 | do { | ||
1742 | ret = hw_read_pci(hw, 0xEC); | ||
1743 | } while (!(ret & 0x800000)); /* i2c ready poll */ | ||
1744 | hw_write_pci(hw, 0xEC, 0x05); /* write to i2c status control */ | ||
1745 | |||
1746 | i2c_write(hw, 0x001a0080, 0x0e, 0x08); | ||
1747 | i2c_write(hw, 0x001a0080, 0x18, 0x0a); | ||
1748 | i2c_write(hw, 0x001a0080, 0x28, 0x86); | ||
1749 | i2c_write(hw, 0x001a0080, 0x2a, adcdata); | ||
1750 | |||
1751 | if (mic20db) { | ||
1752 | i2c_write(hw, 0x001a0080, 0x1c, 0xf7); | ||
1753 | i2c_write(hw, 0x001a0080, 0x1e, 0xf7); | ||
1754 | } else { | ||
1755 | i2c_write(hw, 0x001a0080, 0x1c, 0xcf); | ||
1756 | i2c_write(hw, 0x001a0080, 0x1e, 0xcf); | ||
1757 | } | ||
1758 | |||
1759 | if (!(hw_read_20kx(hw, ID0) & 0x100)) | ||
1760 | i2c_write(hw, 0x001a0080, 0x16, 0x26); | ||
1761 | |||
1762 | i2c_lock(hw); | ||
1763 | |||
1764 | gpioorg = (u16)hw_read_20kx(hw, GPIO); | ||
1765 | gpioorg &= 0xfe7f; | ||
1766 | gpioorg |= input_source; | ||
1767 | hw_write_20kx(hw, GPIO, gpioorg); | ||
1768 | |||
1769 | return 0; | ||
1770 | } | ||
1771 | |||
1772 | static int hw_adc_init(struct hw *hw, const struct adc_conf *info) | ||
1773 | { | ||
1774 | if (hw->model == CTSB055X) | ||
1775 | return adc_init_SB055x(hw, info->input, info->mic20db); | ||
1776 | else | ||
1777 | return adc_init_SBx(hw, info->input, info->mic20db); | ||
1778 | } | ||
1779 | |||
1780 | static int hw_have_digit_io_switch(struct hw *hw) | ||
1781 | { | ||
1782 | /* SB073x and Vista compatible cards have no digit IO switch */ | ||
1783 | return !(hw->model == CTSB073X || hw->model == CTUAA); | ||
1784 | } | ||
1785 | |||
1786 | #define CTLBITS(a, b, c, d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d)) | ||
1787 | |||
1788 | #define UAA_CFG_PWRSTATUS 0x44 | ||
1789 | #define UAA_CFG_SPACE_FLAG 0xA0 | ||
1790 | #define UAA_CORE_CHANGE 0x3FFC | ||
1791 | static int uaa_to_xfi(struct pci_dev *pci) | ||
1792 | { | ||
1793 | unsigned int bar0, bar1, bar2, bar3, bar4, bar5; | ||
1794 | unsigned int cmd, irq, cl_size, l_timer, pwr; | ||
1795 | unsigned int is_uaa; | ||
1796 | unsigned int data[4] = {0}; | ||
1797 | unsigned int io_base; | ||
1798 | void *mem_base; | ||
1799 | int i; | ||
1800 | const u32 CTLX = CTLBITS('C', 'T', 'L', 'X'); | ||
1801 | const u32 CTL_ = CTLBITS('C', 'T', 'L', '-'); | ||
1802 | const u32 CTLF = CTLBITS('C', 'T', 'L', 'F'); | ||
1803 | const u32 CTLi = CTLBITS('C', 'T', 'L', 'i'); | ||
1804 | const u32 CTLA = CTLBITS('C', 'T', 'L', 'A'); | ||
1805 | const u32 CTLZ = CTLBITS('C', 'T', 'L', 'Z'); | ||
1806 | const u32 CTLL = CTLBITS('C', 'T', 'L', 'L'); | ||
1807 | |||
1808 | /* By default, Hendrix card UAA Bar0 should be using memory... */ | ||
1809 | io_base = pci_resource_start(pci, 0); | ||
1810 | mem_base = ioremap(io_base, pci_resource_len(pci, 0)); | ||
1811 | if (NULL == mem_base) | ||
1812 | return -ENOENT; | ||
1813 | |||
1814 | /* Read current mode from Mode Change Register */ | ||
1815 | for (i = 0; i < 4; i++) | ||
1816 | data[i] = readl(mem_base + UAA_CORE_CHANGE); | ||
1817 | |||
1818 | /* Determine current mode... */ | ||
1819 | if (data[0] == CTLA) { | ||
1820 | is_uaa = ((data[1] == CTLZ && data[2] == CTLL | ||
1821 | && data[3] == CTLA) || (data[1] == CTLA | ||
1822 | && data[2] == CTLZ && data[3] == CTLL)); | ||
1823 | } else if (data[0] == CTLZ) { | ||
1824 | is_uaa = (data[1] == CTLL | ||
1825 | && data[2] == CTLA && data[3] == CTLA); | ||
1826 | } else if (data[0] == CTLL) { | ||
1827 | is_uaa = (data[1] == CTLA | ||
1828 | && data[2] == CTLA && data[3] == CTLZ); | ||
1829 | } else { | ||
1830 | is_uaa = 0; | ||
1831 | } | ||
1832 | |||
1833 | if (!is_uaa) { | ||
1834 | /* Not in UAA mode currently. Return directly. */ | ||
1835 | iounmap(mem_base); | ||
1836 | return 0; | ||
1837 | } | ||
1838 | |||
1839 | pci_read_config_dword(pci, PCI_BASE_ADDRESS_0, &bar0); | ||
1840 | pci_read_config_dword(pci, PCI_BASE_ADDRESS_1, &bar1); | ||
1841 | pci_read_config_dword(pci, PCI_BASE_ADDRESS_2, &bar2); | ||
1842 | pci_read_config_dword(pci, PCI_BASE_ADDRESS_3, &bar3); | ||
1843 | pci_read_config_dword(pci, PCI_BASE_ADDRESS_4, &bar4); | ||
1844 | pci_read_config_dword(pci, PCI_BASE_ADDRESS_5, &bar5); | ||
1845 | pci_read_config_dword(pci, PCI_INTERRUPT_LINE, &irq); | ||
1846 | pci_read_config_dword(pci, PCI_CACHE_LINE_SIZE, &cl_size); | ||
1847 | pci_read_config_dword(pci, PCI_LATENCY_TIMER, &l_timer); | ||
1848 | pci_read_config_dword(pci, UAA_CFG_PWRSTATUS, &pwr); | ||
1849 | pci_read_config_dword(pci, PCI_COMMAND, &cmd); | ||
1850 | |||
1851 | /* Set up X-Fi core PCI configuration space. */ | ||
1852 | /* Switch to X-Fi config space with BAR0 exposed. */ | ||
1853 | pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x87654321); | ||
1854 | /* Copy UAA's BAR5 into X-Fi BAR0 */ | ||
1855 | pci_write_config_dword(pci, PCI_BASE_ADDRESS_0, bar5); | ||
1856 | /* Switch to X-Fi config space without BAR0 exposed. */ | ||
1857 | pci_write_config_dword(pci, UAA_CFG_SPACE_FLAG, 0x12345678); | ||
1858 | pci_write_config_dword(pci, PCI_BASE_ADDRESS_1, bar1); | ||
1859 | pci_write_config_dword(pci, PCI_BASE_ADDRESS_2, bar2); | ||
1860 | pci_write_config_dword(pci, PCI_BASE_ADDRESS_3, bar3); | ||
1861 | pci_write_config_dword(pci, PCI_BASE_ADDRESS_4, bar4); | ||
1862 | pci_write_config_dword(pci, PCI_INTERRUPT_LINE, irq); | ||
1863 | pci_write_config_dword(pci, PCI_CACHE_LINE_SIZE, cl_size); | ||
1864 | pci_write_config_dword(pci, PCI_LATENCY_TIMER, l_timer); | ||
1865 | pci_write_config_dword(pci, UAA_CFG_PWRSTATUS, pwr); | ||
1866 | pci_write_config_dword(pci, PCI_COMMAND, cmd); | ||
1867 | |||
1868 | /* Switch to X-Fi mode */ | ||
1869 | writel(CTLX, (mem_base + UAA_CORE_CHANGE)); | ||
1870 | writel(CTL_, (mem_base + UAA_CORE_CHANGE)); | ||
1871 | writel(CTLF, (mem_base + UAA_CORE_CHANGE)); | ||
1872 | writel(CTLi, (mem_base + UAA_CORE_CHANGE)); | ||
1873 | |||
1874 | iounmap(mem_base); | ||
1875 | |||
1876 | return 0; | ||
1877 | } | ||
1878 | |||
1879 | static irqreturn_t ct_20k1_interrupt(int irq, void *dev_id) | ||
1880 | { | ||
1881 | struct hw *hw = dev_id; | ||
1882 | unsigned int status; | ||
1883 | |||
1884 | status = hw_read_20kx(hw, GIP); | ||
1885 | if (!status) | ||
1886 | return IRQ_NONE; | ||
1887 | |||
1888 | if (hw->irq_callback) | ||
1889 | hw->irq_callback(hw->irq_callback_data, status); | ||
1890 | |||
1891 | hw_write_20kx(hw, GIP, status); | ||
1892 | return IRQ_HANDLED; | ||
1893 | } | ||
1894 | |||
1895 | static int hw_card_start(struct hw *hw) | ||
1896 | { | ||
1897 | int err; | ||
1898 | struct pci_dev *pci = hw->pci; | ||
1899 | |||
1900 | err = pci_enable_device(pci); | ||
1901 | if (err < 0) | ||
1902 | return err; | ||
1903 | |||
1904 | /* Set DMA transfer mask */ | ||
1905 | if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || | ||
1906 | pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { | ||
1907 | printk(KERN_ERR "architecture does not support PCI " | ||
1908 | "busmaster DMA with mask 0x%llx\n", | ||
1909 | CT_XFI_DMA_MASK); | ||
1910 | err = -ENXIO; | ||
1911 | goto error1; | ||
1912 | } | ||
1913 | |||
1914 | err = pci_request_regions(pci, "XFi"); | ||
1915 | if (err < 0) | ||
1916 | goto error1; | ||
1917 | |||
1918 | /* Switch to X-Fi mode from UAA mode if neeeded */ | ||
1919 | if (hw->model == CTUAA) { | ||
1920 | err = uaa_to_xfi(pci); | ||
1921 | if (err) | ||
1922 | goto error2; | ||
1923 | |||
1924 | hw->io_base = pci_resource_start(pci, 5); | ||
1925 | } else { | ||
1926 | hw->io_base = pci_resource_start(pci, 0); | ||
1927 | } | ||
1928 | |||
1929 | err = request_irq(pci->irq, ct_20k1_interrupt, IRQF_SHARED, | ||
1930 | "ctxfi", hw); | ||
1931 | if (err < 0) { | ||
1932 | printk(KERN_ERR "XFi: Cannot get irq %d\n", pci->irq); | ||
1933 | goto error2; | ||
1934 | } | ||
1935 | hw->irq = pci->irq; | ||
1936 | |||
1937 | pci_set_master(pci); | ||
1938 | |||
1939 | return 0; | ||
1940 | |||
1941 | error2: | ||
1942 | pci_release_regions(pci); | ||
1943 | hw->io_base = 0; | ||
1944 | error1: | ||
1945 | pci_disable_device(pci); | ||
1946 | return err; | ||
1947 | } | ||
1948 | |||
1949 | static int hw_card_stop(struct hw *hw) | ||
1950 | { | ||
1951 | /* TODO: Disable interrupt and so on... */ | ||
1952 | if (hw->irq >= 0) | ||
1953 | synchronize_irq(hw->irq); | ||
1954 | return 0; | ||
1955 | } | ||
1956 | |||
1957 | static int hw_card_shutdown(struct hw *hw) | ||
1958 | { | ||
1959 | if (hw->irq >= 0) | ||
1960 | free_irq(hw->irq, hw); | ||
1961 | |||
1962 | hw->irq = -1; | ||
1963 | |||
1964 | if (NULL != ((void *)hw->mem_base)) | ||
1965 | iounmap((void *)hw->mem_base); | ||
1966 | |||
1967 | hw->mem_base = (unsigned long)NULL; | ||
1968 | |||
1969 | if (hw->io_base) | ||
1970 | pci_release_regions(hw->pci); | ||
1971 | |||
1972 | hw->io_base = 0; | ||
1973 | |||
1974 | pci_disable_device(hw->pci); | ||
1975 | |||
1976 | return 0; | ||
1977 | } | ||
1978 | |||
1979 | static int hw_card_init(struct hw *hw, struct card_conf *info) | ||
1980 | { | ||
1981 | int err; | ||
1982 | unsigned int gctl; | ||
1983 | u32 data; | ||
1984 | struct dac_conf dac_info = {0}; | ||
1985 | struct adc_conf adc_info = {0}; | ||
1986 | struct daio_conf daio_info = {0}; | ||
1987 | struct trn_conf trn_info = {0}; | ||
1988 | |||
1989 | /* Get PCI io port base address and do Hendrix switch if needed. */ | ||
1990 | if (!hw->io_base) { | ||
1991 | err = hw_card_start(hw); | ||
1992 | if (err) | ||
1993 | return err; | ||
1994 | } | ||
1995 | |||
1996 | /* PLL init */ | ||
1997 | err = hw_pll_init(hw, info->rsr); | ||
1998 | if (err < 0) | ||
1999 | return err; | ||
2000 | |||
2001 | /* kick off auto-init */ | ||
2002 | err = hw_auto_init(hw); | ||
2003 | if (err < 0) | ||
2004 | return err; | ||
2005 | |||
2006 | /* Enable audio ring */ | ||
2007 | gctl = hw_read_20kx(hw, GCTL); | ||
2008 | set_field(&gctl, GCTL_EAC, 1); | ||
2009 | set_field(&gctl, GCTL_DBP, 1); | ||
2010 | set_field(&gctl, GCTL_TBP, 1); | ||
2011 | set_field(&gctl, GCTL_FBP, 1); | ||
2012 | set_field(&gctl, GCTL_ET, 1); | ||
2013 | hw_write_20kx(hw, GCTL, gctl); | ||
2014 | mdelay(10); | ||
2015 | |||
2016 | /* Reset all global pending interrupts */ | ||
2017 | hw_write_20kx(hw, GIE, 0); | ||
2018 | /* Reset all SRC pending interrupts */ | ||
2019 | hw_write_20kx(hw, SRCIP, 0); | ||
2020 | mdelay(30); | ||
2021 | |||
2022 | /* Detect the card ID and configure GPIO accordingly. */ | ||
2023 | switch (hw->model) { | ||
2024 | case CTSB055X: | ||
2025 | hw_write_20kx(hw, GPIOCTL, 0x13fe); | ||
2026 | break; | ||
2027 | case CTSB073X: | ||
2028 | hw_write_20kx(hw, GPIOCTL, 0x00e6); | ||
2029 | break; | ||
2030 | case CTUAA: | ||
2031 | hw_write_20kx(hw, GPIOCTL, 0x00c2); | ||
2032 | break; | ||
2033 | default: | ||
2034 | hw_write_20kx(hw, GPIOCTL, 0x01e6); | ||
2035 | break; | ||
2036 | } | ||
2037 | |||
2038 | trn_info.vm_pgt_phys = info->vm_pgt_phys; | ||
2039 | err = hw_trn_init(hw, &trn_info); | ||
2040 | if (err < 0) | ||
2041 | return err; | ||
2042 | |||
2043 | daio_info.msr = info->msr; | ||
2044 | err = hw_daio_init(hw, &daio_info); | ||
2045 | if (err < 0) | ||
2046 | return err; | ||
2047 | |||
2048 | dac_info.msr = info->msr; | ||
2049 | err = hw_dac_init(hw, &dac_info); | ||
2050 | if (err < 0) | ||
2051 | return err; | ||
2052 | |||
2053 | adc_info.msr = info->msr; | ||
2054 | adc_info.input = ADC_LINEIN; | ||
2055 | adc_info.mic20db = 0; | ||
2056 | err = hw_adc_init(hw, &adc_info); | ||
2057 | if (err < 0) | ||
2058 | return err; | ||
2059 | |||
2060 | data = hw_read_20kx(hw, SRCMCTL); | ||
2061 | data |= 0x1; /* Enables input from the audio ring */ | ||
2062 | hw_write_20kx(hw, SRCMCTL, data); | ||
2063 | |||
2064 | return 0; | ||
2065 | } | ||
2066 | |||
2067 | static u32 hw_read_20kx(struct hw *hw, u32 reg) | ||
2068 | { | ||
2069 | u32 value; | ||
2070 | unsigned long flags; | ||
2071 | |||
2072 | spin_lock_irqsave( | ||
2073 | &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); | ||
2074 | outl(reg, hw->io_base + 0x0); | ||
2075 | value = inl(hw->io_base + 0x4); | ||
2076 | spin_unlock_irqrestore( | ||
2077 | &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); | ||
2078 | |||
2079 | return value; | ||
2080 | } | ||
2081 | |||
2082 | static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) | ||
2083 | { | ||
2084 | unsigned long flags; | ||
2085 | |||
2086 | spin_lock_irqsave( | ||
2087 | &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); | ||
2088 | outl(reg, hw->io_base + 0x0); | ||
2089 | outl(data, hw->io_base + 0x4); | ||
2090 | spin_unlock_irqrestore( | ||
2091 | &container_of(hw, struct hw20k1, hw)->reg_20k1_lock, flags); | ||
2092 | |||
2093 | } | ||
2094 | |||
2095 | static u32 hw_read_pci(struct hw *hw, u32 reg) | ||
2096 | { | ||
2097 | u32 value; | ||
2098 | unsigned long flags; | ||
2099 | |||
2100 | spin_lock_irqsave( | ||
2101 | &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); | ||
2102 | outl(reg, hw->io_base + 0x10); | ||
2103 | value = inl(hw->io_base + 0x14); | ||
2104 | spin_unlock_irqrestore( | ||
2105 | &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); | ||
2106 | |||
2107 | return value; | ||
2108 | } | ||
2109 | |||
2110 | static void hw_write_pci(struct hw *hw, u32 reg, u32 data) | ||
2111 | { | ||
2112 | unsigned long flags; | ||
2113 | |||
2114 | spin_lock_irqsave( | ||
2115 | &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); | ||
2116 | outl(reg, hw->io_base + 0x10); | ||
2117 | outl(data, hw->io_base + 0x14); | ||
2118 | spin_unlock_irqrestore( | ||
2119 | &container_of(hw, struct hw20k1, hw)->reg_pci_lock, flags); | ||
2120 | } | ||
2121 | |||
2122 | static struct hw ct20k1_preset __devinitdata = { | ||
2123 | .irq = -1, | ||
2124 | |||
2125 | .card_init = hw_card_init, | ||
2126 | .card_stop = hw_card_stop, | ||
2127 | .pll_init = hw_pll_init, | ||
2128 | .is_adc_source_selected = hw_is_adc_input_selected, | ||
2129 | .select_adc_source = hw_adc_input_select, | ||
2130 | .have_digit_io_switch = hw_have_digit_io_switch, | ||
2131 | |||
2132 | .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, | ||
2133 | .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, | ||
2134 | .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk, | ||
2135 | .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk, | ||
2136 | .src_set_state = src_set_state, | ||
2137 | .src_set_bm = src_set_bm, | ||
2138 | .src_set_rsr = src_set_rsr, | ||
2139 | .src_set_sf = src_set_sf, | ||
2140 | .src_set_wr = src_set_wr, | ||
2141 | .src_set_pm = src_set_pm, | ||
2142 | .src_set_rom = src_set_rom, | ||
2143 | .src_set_vo = src_set_vo, | ||
2144 | .src_set_st = src_set_st, | ||
2145 | .src_set_ie = src_set_ie, | ||
2146 | .src_set_ilsz = src_set_ilsz, | ||
2147 | .src_set_bp = src_set_bp, | ||
2148 | .src_set_cisz = src_set_cisz, | ||
2149 | .src_set_ca = src_set_ca, | ||
2150 | .src_set_sa = src_set_sa, | ||
2151 | .src_set_la = src_set_la, | ||
2152 | .src_set_pitch = src_set_pitch, | ||
2153 | .src_set_dirty = src_set_dirty, | ||
2154 | .src_set_clear_zbufs = src_set_clear_zbufs, | ||
2155 | .src_set_dirty_all = src_set_dirty_all, | ||
2156 | .src_commit_write = src_commit_write, | ||
2157 | .src_get_ca = src_get_ca, | ||
2158 | .src_get_dirty = src_get_dirty, | ||
2159 | .src_dirty_conj_mask = src_dirty_conj_mask, | ||
2160 | .src_mgr_enbs_src = src_mgr_enbs_src, | ||
2161 | .src_mgr_enb_src = src_mgr_enb_src, | ||
2162 | .src_mgr_dsb_src = src_mgr_dsb_src, | ||
2163 | .src_mgr_commit_write = src_mgr_commit_write, | ||
2164 | |||
2165 | .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk, | ||
2166 | .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk, | ||
2167 | .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc, | ||
2168 | .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser, | ||
2169 | .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt, | ||
2170 | .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr, | ||
2171 | .srcimp_mgr_commit_write = srcimp_mgr_commit_write, | ||
2172 | |||
2173 | .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk, | ||
2174 | .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk, | ||
2175 | .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk, | ||
2176 | .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk, | ||
2177 | .amixer_set_mode = amixer_set_mode, | ||
2178 | .amixer_set_iv = amixer_set_iv, | ||
2179 | .amixer_set_x = amixer_set_x, | ||
2180 | .amixer_set_y = amixer_set_y, | ||
2181 | .amixer_set_sadr = amixer_set_sadr, | ||
2182 | .amixer_set_se = amixer_set_se, | ||
2183 | .amixer_set_dirty = amixer_set_dirty, | ||
2184 | .amixer_set_dirty_all = amixer_set_dirty_all, | ||
2185 | .amixer_commit_write = amixer_commit_write, | ||
2186 | .amixer_get_y = amixer_get_y, | ||
2187 | .amixer_get_dirty = amixer_get_dirty, | ||
2188 | |||
2189 | .dai_get_ctrl_blk = dai_get_ctrl_blk, | ||
2190 | .dai_put_ctrl_blk = dai_put_ctrl_blk, | ||
2191 | .dai_srt_set_srco = dai_srt_set_srcr, | ||
2192 | .dai_srt_set_srcm = dai_srt_set_srcl, | ||
2193 | .dai_srt_set_rsr = dai_srt_set_rsr, | ||
2194 | .dai_srt_set_drat = dai_srt_set_drat, | ||
2195 | .dai_srt_set_ec = dai_srt_set_ec, | ||
2196 | .dai_srt_set_et = dai_srt_set_et, | ||
2197 | .dai_commit_write = dai_commit_write, | ||
2198 | |||
2199 | .dao_get_ctrl_blk = dao_get_ctrl_blk, | ||
2200 | .dao_put_ctrl_blk = dao_put_ctrl_blk, | ||
2201 | .dao_set_spos = dao_set_spos, | ||
2202 | .dao_commit_write = dao_commit_write, | ||
2203 | .dao_get_spos = dao_get_spos, | ||
2204 | |||
2205 | .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk, | ||
2206 | .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk, | ||
2207 | .daio_mgr_enb_dai = daio_mgr_enb_dai, | ||
2208 | .daio_mgr_dsb_dai = daio_mgr_dsb_dai, | ||
2209 | .daio_mgr_enb_dao = daio_mgr_enb_dao, | ||
2210 | .daio_mgr_dsb_dao = daio_mgr_dsb_dao, | ||
2211 | .daio_mgr_dao_init = daio_mgr_dao_init, | ||
2212 | .daio_mgr_set_imaparc = daio_mgr_set_imaparc, | ||
2213 | .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt, | ||
2214 | .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr, | ||
2215 | .daio_mgr_commit_write = daio_mgr_commit_write, | ||
2216 | |||
2217 | .set_timer_irq = set_timer_irq, | ||
2218 | .set_timer_tick = set_timer_tick, | ||
2219 | .get_wc = get_wc, | ||
2220 | }; | ||
2221 | |||
2222 | int __devinit create_20k1_hw_obj(struct hw **rhw) | ||
2223 | { | ||
2224 | struct hw20k1 *hw20k1; | ||
2225 | |||
2226 | *rhw = NULL; | ||
2227 | hw20k1 = kzalloc(sizeof(*hw20k1), GFP_KERNEL); | ||
2228 | if (NULL == hw20k1) | ||
2229 | return -ENOMEM; | ||
2230 | |||
2231 | spin_lock_init(&hw20k1->reg_20k1_lock); | ||
2232 | spin_lock_init(&hw20k1->reg_pci_lock); | ||
2233 | |||
2234 | hw20k1->hw = ct20k1_preset; | ||
2235 | |||
2236 | *rhw = &hw20k1->hw; | ||
2237 | |||
2238 | return 0; | ||
2239 | } | ||
2240 | |||
2241 | int destroy_20k1_hw_obj(struct hw *hw) | ||
2242 | { | ||
2243 | if (hw->io_base) | ||
2244 | hw_card_shutdown(hw); | ||
2245 | |||
2246 | kfree(container_of(hw, struct hw20k1, hw)); | ||
2247 | return 0; | ||
2248 | } | ||
diff --git a/sound/pci/ctxfi/cthw20k1.h b/sound/pci/ctxfi/cthw20k1.h new file mode 100644 index 000000000000..02f72fb448a6 --- /dev/null +++ b/sound/pci/ctxfi/cthw20k1.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File cthw20k1.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of hardware access methord. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date May 13 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef CTHW20K1_H | ||
19 | #define CTHW20K1_H | ||
20 | |||
21 | #include "cthardware.h" | ||
22 | |||
23 | int create_20k1_hw_obj(struct hw **rhw); | ||
24 | int destroy_20k1_hw_obj(struct hw *hw); | ||
25 | |||
26 | #endif /* CTHW20K1_H */ | ||
diff --git a/sound/pci/ctxfi/cthw20k2.c b/sound/pci/ctxfi/cthw20k2.c new file mode 100644 index 000000000000..4493a51c6b01 --- /dev/null +++ b/sound/pci/ctxfi/cthw20k2.c | |||
@@ -0,0 +1,2137 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File cthw20k2.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of hardware access methord for 20k2. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date May 14 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include <linux/types.h> | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <linux/string.h> | ||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/interrupt.h> | ||
25 | #include <linux/delay.h> | ||
26 | #include "cthw20k2.h" | ||
27 | #include "ct20k2reg.h" | ||
28 | |||
29 | #if BITS_PER_LONG == 32 | ||
30 | #define CT_XFI_DMA_MASK DMA_BIT_MASK(32) /* 32 bit PTE */ | ||
31 | #else | ||
32 | #define CT_XFI_DMA_MASK DMA_BIT_MASK(64) /* 64 bit PTE */ | ||
33 | #endif | ||
34 | |||
35 | struct hw20k2 { | ||
36 | struct hw hw; | ||
37 | /* for i2c */ | ||
38 | unsigned char dev_id; | ||
39 | unsigned char addr_size; | ||
40 | unsigned char data_size; | ||
41 | }; | ||
42 | |||
43 | static u32 hw_read_20kx(struct hw *hw, u32 reg); | ||
44 | static void hw_write_20kx(struct hw *hw, u32 reg, u32 data); | ||
45 | |||
46 | /* | ||
47 | * Type definition block. | ||
48 | * The layout of control structures can be directly applied on 20k2 chip. | ||
49 | */ | ||
50 | |||
51 | /* | ||
52 | * SRC control block definitions. | ||
53 | */ | ||
54 | |||
55 | /* SRC resource control block */ | ||
56 | #define SRCCTL_STATE 0x00000007 | ||
57 | #define SRCCTL_BM 0x00000008 | ||
58 | #define SRCCTL_RSR 0x00000030 | ||
59 | #define SRCCTL_SF 0x000001C0 | ||
60 | #define SRCCTL_WR 0x00000200 | ||
61 | #define SRCCTL_PM 0x00000400 | ||
62 | #define SRCCTL_ROM 0x00001800 | ||
63 | #define SRCCTL_VO 0x00002000 | ||
64 | #define SRCCTL_ST 0x00004000 | ||
65 | #define SRCCTL_IE 0x00008000 | ||
66 | #define SRCCTL_ILSZ 0x000F0000 | ||
67 | #define SRCCTL_BP 0x00100000 | ||
68 | |||
69 | #define SRCCCR_CISZ 0x000007FF | ||
70 | #define SRCCCR_CWA 0x001FF800 | ||
71 | #define SRCCCR_D 0x00200000 | ||
72 | #define SRCCCR_RS 0x01C00000 | ||
73 | #define SRCCCR_NAL 0x3E000000 | ||
74 | #define SRCCCR_RA 0xC0000000 | ||
75 | |||
76 | #define SRCCA_CA 0x0FFFFFFF | ||
77 | #define SRCCA_RS 0xE0000000 | ||
78 | |||
79 | #define SRCSA_SA 0x0FFFFFFF | ||
80 | |||
81 | #define SRCLA_LA 0x0FFFFFFF | ||
82 | |||
83 | /* Mixer Parameter Ring ram Low and Hight register. | ||
84 | * Fixed-point value in 8.24 format for parameter channel */ | ||
85 | #define MPRLH_PITCH 0xFFFFFFFF | ||
86 | |||
87 | /* SRC resource register dirty flags */ | ||
88 | union src_dirty { | ||
89 | struct { | ||
90 | u16 ctl:1; | ||
91 | u16 ccr:1; | ||
92 | u16 sa:1; | ||
93 | u16 la:1; | ||
94 | u16 ca:1; | ||
95 | u16 mpr:1; | ||
96 | u16 czbfs:1; /* Clear Z-Buffers */ | ||
97 | u16 rsv:9; | ||
98 | } bf; | ||
99 | u16 data; | ||
100 | }; | ||
101 | |||
102 | struct src_rsc_ctrl_blk { | ||
103 | unsigned int ctl; | ||
104 | unsigned int ccr; | ||
105 | unsigned int ca; | ||
106 | unsigned int sa; | ||
107 | unsigned int la; | ||
108 | unsigned int mpr; | ||
109 | union src_dirty dirty; | ||
110 | }; | ||
111 | |||
112 | /* SRC manager control block */ | ||
113 | union src_mgr_dirty { | ||
114 | struct { | ||
115 | u16 enb0:1; | ||
116 | u16 enb1:1; | ||
117 | u16 enb2:1; | ||
118 | u16 enb3:1; | ||
119 | u16 enb4:1; | ||
120 | u16 enb5:1; | ||
121 | u16 enb6:1; | ||
122 | u16 enb7:1; | ||
123 | u16 enbsa:1; | ||
124 | u16 rsv:7; | ||
125 | } bf; | ||
126 | u16 data; | ||
127 | }; | ||
128 | |||
129 | struct src_mgr_ctrl_blk { | ||
130 | unsigned int enbsa; | ||
131 | unsigned int enb[8]; | ||
132 | union src_mgr_dirty dirty; | ||
133 | }; | ||
134 | |||
135 | /* SRCIMP manager control block */ | ||
136 | #define SRCAIM_ARC 0x00000FFF | ||
137 | #define SRCAIM_NXT 0x00FF0000 | ||
138 | #define SRCAIM_SRC 0xFF000000 | ||
139 | |||
140 | struct srcimap { | ||
141 | unsigned int srcaim; | ||
142 | unsigned int idx; | ||
143 | }; | ||
144 | |||
145 | /* SRCIMP manager register dirty flags */ | ||
146 | union srcimp_mgr_dirty { | ||
147 | struct { | ||
148 | u16 srcimap:1; | ||
149 | u16 rsv:15; | ||
150 | } bf; | ||
151 | u16 data; | ||
152 | }; | ||
153 | |||
154 | struct srcimp_mgr_ctrl_blk { | ||
155 | struct srcimap srcimap; | ||
156 | union srcimp_mgr_dirty dirty; | ||
157 | }; | ||
158 | |||
159 | /* | ||
160 | * Function implementation block. | ||
161 | */ | ||
162 | |||
163 | static int src_get_rsc_ctrl_blk(void **rblk) | ||
164 | { | ||
165 | struct src_rsc_ctrl_blk *blk; | ||
166 | |||
167 | *rblk = NULL; | ||
168 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
169 | if (NULL == blk) | ||
170 | return -ENOMEM; | ||
171 | |||
172 | *rblk = blk; | ||
173 | |||
174 | return 0; | ||
175 | } | ||
176 | |||
177 | static int src_put_rsc_ctrl_blk(void *blk) | ||
178 | { | ||
179 | kfree(blk); | ||
180 | |||
181 | return 0; | ||
182 | } | ||
183 | |||
184 | static int src_set_state(void *blk, unsigned int state) | ||
185 | { | ||
186 | struct src_rsc_ctrl_blk *ctl = blk; | ||
187 | |||
188 | set_field(&ctl->ctl, SRCCTL_STATE, state); | ||
189 | ctl->dirty.bf.ctl = 1; | ||
190 | return 0; | ||
191 | } | ||
192 | |||
193 | static int src_set_bm(void *blk, unsigned int bm) | ||
194 | { | ||
195 | struct src_rsc_ctrl_blk *ctl = blk; | ||
196 | |||
197 | set_field(&ctl->ctl, SRCCTL_BM, bm); | ||
198 | ctl->dirty.bf.ctl = 1; | ||
199 | return 0; | ||
200 | } | ||
201 | |||
202 | static int src_set_rsr(void *blk, unsigned int rsr) | ||
203 | { | ||
204 | struct src_rsc_ctrl_blk *ctl = blk; | ||
205 | |||
206 | set_field(&ctl->ctl, SRCCTL_RSR, rsr); | ||
207 | ctl->dirty.bf.ctl = 1; | ||
208 | return 0; | ||
209 | } | ||
210 | |||
211 | static int src_set_sf(void *blk, unsigned int sf) | ||
212 | { | ||
213 | struct src_rsc_ctrl_blk *ctl = blk; | ||
214 | |||
215 | set_field(&ctl->ctl, SRCCTL_SF, sf); | ||
216 | ctl->dirty.bf.ctl = 1; | ||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | static int src_set_wr(void *blk, unsigned int wr) | ||
221 | { | ||
222 | struct src_rsc_ctrl_blk *ctl = blk; | ||
223 | |||
224 | set_field(&ctl->ctl, SRCCTL_WR, wr); | ||
225 | ctl->dirty.bf.ctl = 1; | ||
226 | return 0; | ||
227 | } | ||
228 | |||
229 | static int src_set_pm(void *blk, unsigned int pm) | ||
230 | { | ||
231 | struct src_rsc_ctrl_blk *ctl = blk; | ||
232 | |||
233 | set_field(&ctl->ctl, SRCCTL_PM, pm); | ||
234 | ctl->dirty.bf.ctl = 1; | ||
235 | return 0; | ||
236 | } | ||
237 | |||
238 | static int src_set_rom(void *blk, unsigned int rom) | ||
239 | { | ||
240 | struct src_rsc_ctrl_blk *ctl = blk; | ||
241 | |||
242 | set_field(&ctl->ctl, SRCCTL_ROM, rom); | ||
243 | ctl->dirty.bf.ctl = 1; | ||
244 | return 0; | ||
245 | } | ||
246 | |||
247 | static int src_set_vo(void *blk, unsigned int vo) | ||
248 | { | ||
249 | struct src_rsc_ctrl_blk *ctl = blk; | ||
250 | |||
251 | set_field(&ctl->ctl, SRCCTL_VO, vo); | ||
252 | ctl->dirty.bf.ctl = 1; | ||
253 | return 0; | ||
254 | } | ||
255 | |||
256 | static int src_set_st(void *blk, unsigned int st) | ||
257 | { | ||
258 | struct src_rsc_ctrl_blk *ctl = blk; | ||
259 | |||
260 | set_field(&ctl->ctl, SRCCTL_ST, st); | ||
261 | ctl->dirty.bf.ctl = 1; | ||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static int src_set_ie(void *blk, unsigned int ie) | ||
266 | { | ||
267 | struct src_rsc_ctrl_blk *ctl = blk; | ||
268 | |||
269 | set_field(&ctl->ctl, SRCCTL_IE, ie); | ||
270 | ctl->dirty.bf.ctl = 1; | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int src_set_ilsz(void *blk, unsigned int ilsz) | ||
275 | { | ||
276 | struct src_rsc_ctrl_blk *ctl = blk; | ||
277 | |||
278 | set_field(&ctl->ctl, SRCCTL_ILSZ, ilsz); | ||
279 | ctl->dirty.bf.ctl = 1; | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static int src_set_bp(void *blk, unsigned int bp) | ||
284 | { | ||
285 | struct src_rsc_ctrl_blk *ctl = blk; | ||
286 | |||
287 | set_field(&ctl->ctl, SRCCTL_BP, bp); | ||
288 | ctl->dirty.bf.ctl = 1; | ||
289 | return 0; | ||
290 | } | ||
291 | |||
292 | static int src_set_cisz(void *blk, unsigned int cisz) | ||
293 | { | ||
294 | struct src_rsc_ctrl_blk *ctl = blk; | ||
295 | |||
296 | set_field(&ctl->ccr, SRCCCR_CISZ, cisz); | ||
297 | ctl->dirty.bf.ccr = 1; | ||
298 | return 0; | ||
299 | } | ||
300 | |||
301 | static int src_set_ca(void *blk, unsigned int ca) | ||
302 | { | ||
303 | struct src_rsc_ctrl_blk *ctl = blk; | ||
304 | |||
305 | set_field(&ctl->ca, SRCCA_CA, ca); | ||
306 | ctl->dirty.bf.ca = 1; | ||
307 | return 0; | ||
308 | } | ||
309 | |||
310 | static int src_set_sa(void *blk, unsigned int sa) | ||
311 | { | ||
312 | struct src_rsc_ctrl_blk *ctl = blk; | ||
313 | |||
314 | set_field(&ctl->sa, SRCSA_SA, sa); | ||
315 | ctl->dirty.bf.sa = 1; | ||
316 | return 0; | ||
317 | } | ||
318 | |||
319 | static int src_set_la(void *blk, unsigned int la) | ||
320 | { | ||
321 | struct src_rsc_ctrl_blk *ctl = blk; | ||
322 | |||
323 | set_field(&ctl->la, SRCLA_LA, la); | ||
324 | ctl->dirty.bf.la = 1; | ||
325 | return 0; | ||
326 | } | ||
327 | |||
328 | static int src_set_pitch(void *blk, unsigned int pitch) | ||
329 | { | ||
330 | struct src_rsc_ctrl_blk *ctl = blk; | ||
331 | |||
332 | set_field(&ctl->mpr, MPRLH_PITCH, pitch); | ||
333 | ctl->dirty.bf.mpr = 1; | ||
334 | return 0; | ||
335 | } | ||
336 | |||
337 | static int src_set_clear_zbufs(void *blk, unsigned int clear) | ||
338 | { | ||
339 | ((struct src_rsc_ctrl_blk *)blk)->dirty.bf.czbfs = (clear ? 1 : 0); | ||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int src_set_dirty(void *blk, unsigned int flags) | ||
344 | { | ||
345 | ((struct src_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); | ||
346 | return 0; | ||
347 | } | ||
348 | |||
349 | static int src_set_dirty_all(void *blk) | ||
350 | { | ||
351 | ((struct src_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); | ||
352 | return 0; | ||
353 | } | ||
354 | |||
355 | #define AR_SLOT_SIZE 4096 | ||
356 | #define AR_SLOT_BLOCK_SIZE 16 | ||
357 | #define AR_PTS_PITCH 6 | ||
358 | #define AR_PARAM_SRC_OFFSET 0x60 | ||
359 | |||
360 | static unsigned int src_param_pitch_mixer(unsigned int src_idx) | ||
361 | { | ||
362 | return ((src_idx << 4) + AR_PTS_PITCH + AR_SLOT_SIZE | ||
363 | - AR_PARAM_SRC_OFFSET) % AR_SLOT_SIZE; | ||
364 | |||
365 | } | ||
366 | |||
367 | static int src_commit_write(struct hw *hw, unsigned int idx, void *blk) | ||
368 | { | ||
369 | struct src_rsc_ctrl_blk *ctl = blk; | ||
370 | int i; | ||
371 | |||
372 | if (ctl->dirty.bf.czbfs) { | ||
373 | /* Clear Z-Buffer registers */ | ||
374 | for (i = 0; i < 8; i++) | ||
375 | hw_write_20kx(hw, SRC_UPZ+idx*0x100+i*0x4, 0); | ||
376 | |||
377 | for (i = 0; i < 4; i++) | ||
378 | hw_write_20kx(hw, SRC_DN0Z+idx*0x100+i*0x4, 0); | ||
379 | |||
380 | for (i = 0; i < 8; i++) | ||
381 | hw_write_20kx(hw, SRC_DN1Z+idx*0x100+i*0x4, 0); | ||
382 | |||
383 | ctl->dirty.bf.czbfs = 0; | ||
384 | } | ||
385 | if (ctl->dirty.bf.mpr) { | ||
386 | /* Take the parameter mixer resource in the same group as that | ||
387 | * the idx src is in for simplicity. Unlike src, all conjugate | ||
388 | * parameter mixer resources must be programmed for | ||
389 | * corresponding conjugate src resources. */ | ||
390 | unsigned int pm_idx = src_param_pitch_mixer(idx); | ||
391 | hw_write_20kx(hw, MIXER_PRING_LO_HI+4*pm_idx, ctl->mpr); | ||
392 | hw_write_20kx(hw, MIXER_PMOPLO+8*pm_idx, 0x3); | ||
393 | hw_write_20kx(hw, MIXER_PMOPHI+8*pm_idx, 0x0); | ||
394 | ctl->dirty.bf.mpr = 0; | ||
395 | } | ||
396 | if (ctl->dirty.bf.sa) { | ||
397 | hw_write_20kx(hw, SRC_SA+idx*0x100, ctl->sa); | ||
398 | ctl->dirty.bf.sa = 0; | ||
399 | } | ||
400 | if (ctl->dirty.bf.la) { | ||
401 | hw_write_20kx(hw, SRC_LA+idx*0x100, ctl->la); | ||
402 | ctl->dirty.bf.la = 0; | ||
403 | } | ||
404 | if (ctl->dirty.bf.ca) { | ||
405 | hw_write_20kx(hw, SRC_CA+idx*0x100, ctl->ca); | ||
406 | ctl->dirty.bf.ca = 0; | ||
407 | } | ||
408 | |||
409 | /* Write srccf register */ | ||
410 | hw_write_20kx(hw, SRC_CF+idx*0x100, 0x0); | ||
411 | |||
412 | if (ctl->dirty.bf.ccr) { | ||
413 | hw_write_20kx(hw, SRC_CCR+idx*0x100, ctl->ccr); | ||
414 | ctl->dirty.bf.ccr = 0; | ||
415 | } | ||
416 | if (ctl->dirty.bf.ctl) { | ||
417 | hw_write_20kx(hw, SRC_CTL+idx*0x100, ctl->ctl); | ||
418 | ctl->dirty.bf.ctl = 0; | ||
419 | } | ||
420 | |||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static int src_get_ca(struct hw *hw, unsigned int idx, void *blk) | ||
425 | { | ||
426 | struct src_rsc_ctrl_blk *ctl = blk; | ||
427 | |||
428 | ctl->ca = hw_read_20kx(hw, SRC_CA+idx*0x100); | ||
429 | ctl->dirty.bf.ca = 0; | ||
430 | |||
431 | return get_field(ctl->ca, SRCCA_CA); | ||
432 | } | ||
433 | |||
434 | static unsigned int src_get_dirty(void *blk) | ||
435 | { | ||
436 | return ((struct src_rsc_ctrl_blk *)blk)->dirty.data; | ||
437 | } | ||
438 | |||
439 | static unsigned int src_dirty_conj_mask(void) | ||
440 | { | ||
441 | return 0x20; | ||
442 | } | ||
443 | |||
444 | static int src_mgr_enbs_src(void *blk, unsigned int idx) | ||
445 | { | ||
446 | ((struct src_mgr_ctrl_blk *)blk)->enbsa |= (0x1 << ((idx%128)/4)); | ||
447 | ((struct src_mgr_ctrl_blk *)blk)->dirty.bf.enbsa = 1; | ||
448 | ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); | ||
449 | return 0; | ||
450 | } | ||
451 | |||
452 | static int src_mgr_enb_src(void *blk, unsigned int idx) | ||
453 | { | ||
454 | ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] |= (0x1 << (idx%32)); | ||
455 | ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); | ||
456 | return 0; | ||
457 | } | ||
458 | |||
459 | static int src_mgr_dsb_src(void *blk, unsigned int idx) | ||
460 | { | ||
461 | ((struct src_mgr_ctrl_blk *)blk)->enb[idx/32] &= ~(0x1 << (idx%32)); | ||
462 | ((struct src_mgr_ctrl_blk *)blk)->dirty.data |= (0x1 << (idx/32)); | ||
463 | return 0; | ||
464 | } | ||
465 | |||
466 | static int src_mgr_commit_write(struct hw *hw, void *blk) | ||
467 | { | ||
468 | struct src_mgr_ctrl_blk *ctl = blk; | ||
469 | int i; | ||
470 | unsigned int ret; | ||
471 | |||
472 | if (ctl->dirty.bf.enbsa) { | ||
473 | do { | ||
474 | ret = hw_read_20kx(hw, SRC_ENBSTAT); | ||
475 | } while (ret & 0x1); | ||
476 | hw_write_20kx(hw, SRC_ENBSA, ctl->enbsa); | ||
477 | ctl->dirty.bf.enbsa = 0; | ||
478 | } | ||
479 | for (i = 0; i < 8; i++) { | ||
480 | if ((ctl->dirty.data & (0x1 << i))) { | ||
481 | hw_write_20kx(hw, SRC_ENB+(i*0x100), ctl->enb[i]); | ||
482 | ctl->dirty.data &= ~(0x1 << i); | ||
483 | } | ||
484 | } | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int src_mgr_get_ctrl_blk(void **rblk) | ||
490 | { | ||
491 | struct src_mgr_ctrl_blk *blk; | ||
492 | |||
493 | *rblk = NULL; | ||
494 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
495 | if (NULL == blk) | ||
496 | return -ENOMEM; | ||
497 | |||
498 | *rblk = blk; | ||
499 | |||
500 | return 0; | ||
501 | } | ||
502 | |||
503 | static int src_mgr_put_ctrl_blk(void *blk) | ||
504 | { | ||
505 | kfree(blk); | ||
506 | |||
507 | return 0; | ||
508 | } | ||
509 | |||
510 | static int srcimp_mgr_get_ctrl_blk(void **rblk) | ||
511 | { | ||
512 | struct srcimp_mgr_ctrl_blk *blk; | ||
513 | |||
514 | *rblk = NULL; | ||
515 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
516 | if (NULL == blk) | ||
517 | return -ENOMEM; | ||
518 | |||
519 | *rblk = blk; | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | static int srcimp_mgr_put_ctrl_blk(void *blk) | ||
525 | { | ||
526 | kfree(blk); | ||
527 | |||
528 | return 0; | ||
529 | } | ||
530 | |||
531 | static int srcimp_mgr_set_imaparc(void *blk, unsigned int slot) | ||
532 | { | ||
533 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
534 | |||
535 | set_field(&ctl->srcimap.srcaim, SRCAIM_ARC, slot); | ||
536 | ctl->dirty.bf.srcimap = 1; | ||
537 | return 0; | ||
538 | } | ||
539 | |||
540 | static int srcimp_mgr_set_imapuser(void *blk, unsigned int user) | ||
541 | { | ||
542 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
543 | |||
544 | set_field(&ctl->srcimap.srcaim, SRCAIM_SRC, user); | ||
545 | ctl->dirty.bf.srcimap = 1; | ||
546 | return 0; | ||
547 | } | ||
548 | |||
549 | static int srcimp_mgr_set_imapnxt(void *blk, unsigned int next) | ||
550 | { | ||
551 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
552 | |||
553 | set_field(&ctl->srcimap.srcaim, SRCAIM_NXT, next); | ||
554 | ctl->dirty.bf.srcimap = 1; | ||
555 | return 0; | ||
556 | } | ||
557 | |||
558 | static int srcimp_mgr_set_imapaddr(void *blk, unsigned int addr) | ||
559 | { | ||
560 | ((struct srcimp_mgr_ctrl_blk *)blk)->srcimap.idx = addr; | ||
561 | ((struct srcimp_mgr_ctrl_blk *)blk)->dirty.bf.srcimap = 1; | ||
562 | return 0; | ||
563 | } | ||
564 | |||
565 | static int srcimp_mgr_commit_write(struct hw *hw, void *blk) | ||
566 | { | ||
567 | struct srcimp_mgr_ctrl_blk *ctl = blk; | ||
568 | |||
569 | if (ctl->dirty.bf.srcimap) { | ||
570 | hw_write_20kx(hw, SRC_IMAP+ctl->srcimap.idx*0x100, | ||
571 | ctl->srcimap.srcaim); | ||
572 | ctl->dirty.bf.srcimap = 0; | ||
573 | } | ||
574 | |||
575 | return 0; | ||
576 | } | ||
577 | |||
578 | /* | ||
579 | * AMIXER control block definitions. | ||
580 | */ | ||
581 | |||
582 | #define AMOPLO_M 0x00000003 | ||
583 | #define AMOPLO_IV 0x00000004 | ||
584 | #define AMOPLO_X 0x0003FFF0 | ||
585 | #define AMOPLO_Y 0xFFFC0000 | ||
586 | |||
587 | #define AMOPHI_SADR 0x000000FF | ||
588 | #define AMOPHI_SE 0x80000000 | ||
589 | |||
590 | /* AMIXER resource register dirty flags */ | ||
591 | union amixer_dirty { | ||
592 | struct { | ||
593 | u16 amoplo:1; | ||
594 | u16 amophi:1; | ||
595 | u16 rsv:14; | ||
596 | } bf; | ||
597 | u16 data; | ||
598 | }; | ||
599 | |||
600 | /* AMIXER resource control block */ | ||
601 | struct amixer_rsc_ctrl_blk { | ||
602 | unsigned int amoplo; | ||
603 | unsigned int amophi; | ||
604 | union amixer_dirty dirty; | ||
605 | }; | ||
606 | |||
607 | static int amixer_set_mode(void *blk, unsigned int mode) | ||
608 | { | ||
609 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
610 | |||
611 | set_field(&ctl->amoplo, AMOPLO_M, mode); | ||
612 | ctl->dirty.bf.amoplo = 1; | ||
613 | return 0; | ||
614 | } | ||
615 | |||
616 | static int amixer_set_iv(void *blk, unsigned int iv) | ||
617 | { | ||
618 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
619 | |||
620 | set_field(&ctl->amoplo, AMOPLO_IV, iv); | ||
621 | ctl->dirty.bf.amoplo = 1; | ||
622 | return 0; | ||
623 | } | ||
624 | |||
625 | static int amixer_set_x(void *blk, unsigned int x) | ||
626 | { | ||
627 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
628 | |||
629 | set_field(&ctl->amoplo, AMOPLO_X, x); | ||
630 | ctl->dirty.bf.amoplo = 1; | ||
631 | return 0; | ||
632 | } | ||
633 | |||
634 | static int amixer_set_y(void *blk, unsigned int y) | ||
635 | { | ||
636 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
637 | |||
638 | set_field(&ctl->amoplo, AMOPLO_Y, y); | ||
639 | ctl->dirty.bf.amoplo = 1; | ||
640 | return 0; | ||
641 | } | ||
642 | |||
643 | static int amixer_set_sadr(void *blk, unsigned int sadr) | ||
644 | { | ||
645 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
646 | |||
647 | set_field(&ctl->amophi, AMOPHI_SADR, sadr); | ||
648 | ctl->dirty.bf.amophi = 1; | ||
649 | return 0; | ||
650 | } | ||
651 | |||
652 | static int amixer_set_se(void *blk, unsigned int se) | ||
653 | { | ||
654 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
655 | |||
656 | set_field(&ctl->amophi, AMOPHI_SE, se); | ||
657 | ctl->dirty.bf.amophi = 1; | ||
658 | return 0; | ||
659 | } | ||
660 | |||
661 | static int amixer_set_dirty(void *blk, unsigned int flags) | ||
662 | { | ||
663 | ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = (flags & 0xffff); | ||
664 | return 0; | ||
665 | } | ||
666 | |||
667 | static int amixer_set_dirty_all(void *blk) | ||
668 | { | ||
669 | ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data = ~(0x0); | ||
670 | return 0; | ||
671 | } | ||
672 | |||
673 | static int amixer_commit_write(struct hw *hw, unsigned int idx, void *blk) | ||
674 | { | ||
675 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
676 | |||
677 | if (ctl->dirty.bf.amoplo || ctl->dirty.bf.amophi) { | ||
678 | hw_write_20kx(hw, MIXER_AMOPLO+idx*8, ctl->amoplo); | ||
679 | ctl->dirty.bf.amoplo = 0; | ||
680 | hw_write_20kx(hw, MIXER_AMOPHI+idx*8, ctl->amophi); | ||
681 | ctl->dirty.bf.amophi = 0; | ||
682 | } | ||
683 | |||
684 | return 0; | ||
685 | } | ||
686 | |||
687 | static int amixer_get_y(void *blk) | ||
688 | { | ||
689 | struct amixer_rsc_ctrl_blk *ctl = blk; | ||
690 | |||
691 | return get_field(ctl->amoplo, AMOPLO_Y); | ||
692 | } | ||
693 | |||
694 | static unsigned int amixer_get_dirty(void *blk) | ||
695 | { | ||
696 | return ((struct amixer_rsc_ctrl_blk *)blk)->dirty.data; | ||
697 | } | ||
698 | |||
699 | static int amixer_rsc_get_ctrl_blk(void **rblk) | ||
700 | { | ||
701 | struct amixer_rsc_ctrl_blk *blk; | ||
702 | |||
703 | *rblk = NULL; | ||
704 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
705 | if (NULL == blk) | ||
706 | return -ENOMEM; | ||
707 | |||
708 | *rblk = blk; | ||
709 | |||
710 | return 0; | ||
711 | } | ||
712 | |||
713 | static int amixer_rsc_put_ctrl_blk(void *blk) | ||
714 | { | ||
715 | kfree(blk); | ||
716 | |||
717 | return 0; | ||
718 | } | ||
719 | |||
720 | static int amixer_mgr_get_ctrl_blk(void **rblk) | ||
721 | { | ||
722 | *rblk = NULL; | ||
723 | |||
724 | return 0; | ||
725 | } | ||
726 | |||
727 | static int amixer_mgr_put_ctrl_blk(void *blk) | ||
728 | { | ||
729 | return 0; | ||
730 | } | ||
731 | |||
732 | /* | ||
733 | * DAIO control block definitions. | ||
734 | */ | ||
735 | |||
736 | /* Receiver Sample Rate Tracker Control register */ | ||
737 | #define SRTCTL_SRCO 0x000000FF | ||
738 | #define SRTCTL_SRCM 0x0000FF00 | ||
739 | #define SRTCTL_RSR 0x00030000 | ||
740 | #define SRTCTL_DRAT 0x00300000 | ||
741 | #define SRTCTL_EC 0x01000000 | ||
742 | #define SRTCTL_ET 0x10000000 | ||
743 | |||
744 | /* DAIO Receiver register dirty flags */ | ||
745 | union dai_dirty { | ||
746 | struct { | ||
747 | u16 srt:1; | ||
748 | u16 rsv:15; | ||
749 | } bf; | ||
750 | u16 data; | ||
751 | }; | ||
752 | |||
753 | /* DAIO Receiver control block */ | ||
754 | struct dai_ctrl_blk { | ||
755 | unsigned int srt; | ||
756 | union dai_dirty dirty; | ||
757 | }; | ||
758 | |||
759 | /* Audio Input Mapper RAM */ | ||
760 | #define AIM_ARC 0x00000FFF | ||
761 | #define AIM_NXT 0x007F0000 | ||
762 | |||
763 | struct daoimap { | ||
764 | unsigned int aim; | ||
765 | unsigned int idx; | ||
766 | }; | ||
767 | |||
768 | /* Audio Transmitter Control and Status register */ | ||
769 | #define ATXCTL_EN 0x00000001 | ||
770 | #define ATXCTL_MODE 0x00000010 | ||
771 | #define ATXCTL_CD 0x00000020 | ||
772 | #define ATXCTL_RAW 0x00000100 | ||
773 | #define ATXCTL_MT 0x00000200 | ||
774 | #define ATXCTL_NUC 0x00003000 | ||
775 | #define ATXCTL_BEN 0x00010000 | ||
776 | #define ATXCTL_BMUX 0x00700000 | ||
777 | #define ATXCTL_B24 0x01000000 | ||
778 | #define ATXCTL_CPF 0x02000000 | ||
779 | #define ATXCTL_RIV 0x10000000 | ||
780 | #define ATXCTL_LIV 0x20000000 | ||
781 | #define ATXCTL_RSAT 0x40000000 | ||
782 | #define ATXCTL_LSAT 0x80000000 | ||
783 | |||
784 | /* XDIF Transmitter register dirty flags */ | ||
785 | union dao_dirty { | ||
786 | struct { | ||
787 | u16 atxcsl:1; | ||
788 | u16 rsv:15; | ||
789 | } bf; | ||
790 | u16 data; | ||
791 | }; | ||
792 | |||
793 | /* XDIF Transmitter control block */ | ||
794 | struct dao_ctrl_blk { | ||
795 | /* XDIF Transmitter Channel Status Low Register */ | ||
796 | unsigned int atxcsl; | ||
797 | union dao_dirty dirty; | ||
798 | }; | ||
799 | |||
800 | /* Audio Receiver Control register */ | ||
801 | #define ARXCTL_EN 0x00000001 | ||
802 | |||
803 | /* DAIO manager register dirty flags */ | ||
804 | union daio_mgr_dirty { | ||
805 | struct { | ||
806 | u32 atxctl:8; | ||
807 | u32 arxctl:8; | ||
808 | u32 daoimap:1; | ||
809 | u32 rsv:15; | ||
810 | } bf; | ||
811 | u32 data; | ||
812 | }; | ||
813 | |||
814 | /* DAIO manager control block */ | ||
815 | struct daio_mgr_ctrl_blk { | ||
816 | struct daoimap daoimap; | ||
817 | unsigned int txctl[8]; | ||
818 | unsigned int rxctl[8]; | ||
819 | union daio_mgr_dirty dirty; | ||
820 | }; | ||
821 | |||
822 | static int dai_srt_set_srco(void *blk, unsigned int src) | ||
823 | { | ||
824 | struct dai_ctrl_blk *ctl = blk; | ||
825 | |||
826 | set_field(&ctl->srt, SRTCTL_SRCO, src); | ||
827 | ctl->dirty.bf.srt = 1; | ||
828 | return 0; | ||
829 | } | ||
830 | |||
831 | static int dai_srt_set_srcm(void *blk, unsigned int src) | ||
832 | { | ||
833 | struct dai_ctrl_blk *ctl = blk; | ||
834 | |||
835 | set_field(&ctl->srt, SRTCTL_SRCM, src); | ||
836 | ctl->dirty.bf.srt = 1; | ||
837 | return 0; | ||
838 | } | ||
839 | |||
840 | static int dai_srt_set_rsr(void *blk, unsigned int rsr) | ||
841 | { | ||
842 | struct dai_ctrl_blk *ctl = blk; | ||
843 | |||
844 | set_field(&ctl->srt, SRTCTL_RSR, rsr); | ||
845 | ctl->dirty.bf.srt = 1; | ||
846 | return 0; | ||
847 | } | ||
848 | |||
849 | static int dai_srt_set_drat(void *blk, unsigned int drat) | ||
850 | { | ||
851 | struct dai_ctrl_blk *ctl = blk; | ||
852 | |||
853 | set_field(&ctl->srt, SRTCTL_DRAT, drat); | ||
854 | ctl->dirty.bf.srt = 1; | ||
855 | return 0; | ||
856 | } | ||
857 | |||
858 | static int dai_srt_set_ec(void *blk, unsigned int ec) | ||
859 | { | ||
860 | struct dai_ctrl_blk *ctl = blk; | ||
861 | |||
862 | set_field(&ctl->srt, SRTCTL_EC, ec ? 1 : 0); | ||
863 | ctl->dirty.bf.srt = 1; | ||
864 | return 0; | ||
865 | } | ||
866 | |||
867 | static int dai_srt_set_et(void *blk, unsigned int et) | ||
868 | { | ||
869 | struct dai_ctrl_blk *ctl = blk; | ||
870 | |||
871 | set_field(&ctl->srt, SRTCTL_ET, et ? 1 : 0); | ||
872 | ctl->dirty.bf.srt = 1; | ||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int dai_commit_write(struct hw *hw, unsigned int idx, void *blk) | ||
877 | { | ||
878 | struct dai_ctrl_blk *ctl = blk; | ||
879 | |||
880 | if (ctl->dirty.bf.srt) { | ||
881 | hw_write_20kx(hw, AUDIO_IO_RX_SRT_CTL+0x40*idx, ctl->srt); | ||
882 | ctl->dirty.bf.srt = 0; | ||
883 | } | ||
884 | |||
885 | return 0; | ||
886 | } | ||
887 | |||
888 | static int dai_get_ctrl_blk(void **rblk) | ||
889 | { | ||
890 | struct dai_ctrl_blk *blk; | ||
891 | |||
892 | *rblk = NULL; | ||
893 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
894 | if (NULL == blk) | ||
895 | return -ENOMEM; | ||
896 | |||
897 | *rblk = blk; | ||
898 | |||
899 | return 0; | ||
900 | } | ||
901 | |||
902 | static int dai_put_ctrl_blk(void *blk) | ||
903 | { | ||
904 | kfree(blk); | ||
905 | |||
906 | return 0; | ||
907 | } | ||
908 | |||
909 | static int dao_set_spos(void *blk, unsigned int spos) | ||
910 | { | ||
911 | ((struct dao_ctrl_blk *)blk)->atxcsl = spos; | ||
912 | ((struct dao_ctrl_blk *)blk)->dirty.bf.atxcsl = 1; | ||
913 | return 0; | ||
914 | } | ||
915 | |||
916 | static int dao_commit_write(struct hw *hw, unsigned int idx, void *blk) | ||
917 | { | ||
918 | struct dao_ctrl_blk *ctl = blk; | ||
919 | |||
920 | if (ctl->dirty.bf.atxcsl) { | ||
921 | if (idx < 4) { | ||
922 | /* S/PDIF SPOSx */ | ||
923 | hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+0x40*idx, | ||
924 | ctl->atxcsl); | ||
925 | } | ||
926 | ctl->dirty.bf.atxcsl = 0; | ||
927 | } | ||
928 | |||
929 | return 0; | ||
930 | } | ||
931 | |||
932 | static int dao_get_spos(void *blk, unsigned int *spos) | ||
933 | { | ||
934 | *spos = ((struct dao_ctrl_blk *)blk)->atxcsl; | ||
935 | return 0; | ||
936 | } | ||
937 | |||
938 | static int dao_get_ctrl_blk(void **rblk) | ||
939 | { | ||
940 | struct dao_ctrl_blk *blk; | ||
941 | |||
942 | *rblk = NULL; | ||
943 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
944 | if (NULL == blk) | ||
945 | return -ENOMEM; | ||
946 | |||
947 | *rblk = blk; | ||
948 | |||
949 | return 0; | ||
950 | } | ||
951 | |||
952 | static int dao_put_ctrl_blk(void *blk) | ||
953 | { | ||
954 | kfree(blk); | ||
955 | |||
956 | return 0; | ||
957 | } | ||
958 | |||
959 | static int daio_mgr_enb_dai(void *blk, unsigned int idx) | ||
960 | { | ||
961 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
962 | |||
963 | set_field(&ctl->rxctl[idx], ARXCTL_EN, 1); | ||
964 | ctl->dirty.bf.arxctl |= (0x1 << idx); | ||
965 | return 0; | ||
966 | } | ||
967 | |||
968 | static int daio_mgr_dsb_dai(void *blk, unsigned int idx) | ||
969 | { | ||
970 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
971 | |||
972 | set_field(&ctl->rxctl[idx], ARXCTL_EN, 0); | ||
973 | |||
974 | ctl->dirty.bf.arxctl |= (0x1 << idx); | ||
975 | return 0; | ||
976 | } | ||
977 | |||
978 | static int daio_mgr_enb_dao(void *blk, unsigned int idx) | ||
979 | { | ||
980 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
981 | |||
982 | set_field(&ctl->txctl[idx], ATXCTL_EN, 1); | ||
983 | ctl->dirty.bf.atxctl |= (0x1 << idx); | ||
984 | return 0; | ||
985 | } | ||
986 | |||
987 | static int daio_mgr_dsb_dao(void *blk, unsigned int idx) | ||
988 | { | ||
989 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
990 | |||
991 | set_field(&ctl->txctl[idx], ATXCTL_EN, 0); | ||
992 | ctl->dirty.bf.atxctl |= (0x1 << idx); | ||
993 | return 0; | ||
994 | } | ||
995 | |||
996 | static int daio_mgr_dao_init(void *blk, unsigned int idx, unsigned int conf) | ||
997 | { | ||
998 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
999 | |||
1000 | if (idx < 4) { | ||
1001 | /* S/PDIF output */ | ||
1002 | switch ((conf & 0x7)) { | ||
1003 | case 1: | ||
1004 | set_field(&ctl->txctl[idx], ATXCTL_NUC, 0); | ||
1005 | break; | ||
1006 | case 2: | ||
1007 | set_field(&ctl->txctl[idx], ATXCTL_NUC, 1); | ||
1008 | break; | ||
1009 | case 4: | ||
1010 | set_field(&ctl->txctl[idx], ATXCTL_NUC, 2); | ||
1011 | break; | ||
1012 | case 8: | ||
1013 | set_field(&ctl->txctl[idx], ATXCTL_NUC, 3); | ||
1014 | break; | ||
1015 | default: | ||
1016 | break; | ||
1017 | } | ||
1018 | /* CDIF */ | ||
1019 | set_field(&ctl->txctl[idx], ATXCTL_CD, (!(conf & 0x7))); | ||
1020 | /* Non-audio */ | ||
1021 | set_field(&ctl->txctl[idx], ATXCTL_LIV, (conf >> 4) & 0x1); | ||
1022 | /* Non-audio */ | ||
1023 | set_field(&ctl->txctl[idx], ATXCTL_RIV, (conf >> 4) & 0x1); | ||
1024 | set_field(&ctl->txctl[idx], ATXCTL_RAW, | ||
1025 | ((conf >> 3) & 0x1) ? 0 : 0); | ||
1026 | ctl->dirty.bf.atxctl |= (0x1 << idx); | ||
1027 | } else { | ||
1028 | /* I2S output */ | ||
1029 | /*idx %= 4; */ | ||
1030 | } | ||
1031 | return 0; | ||
1032 | } | ||
1033 | |||
1034 | static int daio_mgr_set_imaparc(void *blk, unsigned int slot) | ||
1035 | { | ||
1036 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1037 | |||
1038 | set_field(&ctl->daoimap.aim, AIM_ARC, slot); | ||
1039 | ctl->dirty.bf.daoimap = 1; | ||
1040 | return 0; | ||
1041 | } | ||
1042 | |||
1043 | static int daio_mgr_set_imapnxt(void *blk, unsigned int next) | ||
1044 | { | ||
1045 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1046 | |||
1047 | set_field(&ctl->daoimap.aim, AIM_NXT, next); | ||
1048 | ctl->dirty.bf.daoimap = 1; | ||
1049 | return 0; | ||
1050 | } | ||
1051 | |||
1052 | static int daio_mgr_set_imapaddr(void *blk, unsigned int addr) | ||
1053 | { | ||
1054 | ((struct daio_mgr_ctrl_blk *)blk)->daoimap.idx = addr; | ||
1055 | ((struct daio_mgr_ctrl_blk *)blk)->dirty.bf.daoimap = 1; | ||
1056 | return 0; | ||
1057 | } | ||
1058 | |||
1059 | static int daio_mgr_commit_write(struct hw *hw, void *blk) | ||
1060 | { | ||
1061 | struct daio_mgr_ctrl_blk *ctl = blk; | ||
1062 | unsigned int data; | ||
1063 | int i; | ||
1064 | |||
1065 | for (i = 0; i < 8; i++) { | ||
1066 | if ((ctl->dirty.bf.atxctl & (0x1 << i))) { | ||
1067 | data = ctl->txctl[i]; | ||
1068 | hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data); | ||
1069 | ctl->dirty.bf.atxctl &= ~(0x1 << i); | ||
1070 | mdelay(1); | ||
1071 | } | ||
1072 | if ((ctl->dirty.bf.arxctl & (0x1 << i))) { | ||
1073 | data = ctl->rxctl[i]; | ||
1074 | hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data); | ||
1075 | ctl->dirty.bf.arxctl &= ~(0x1 << i); | ||
1076 | mdelay(1); | ||
1077 | } | ||
1078 | } | ||
1079 | if (ctl->dirty.bf.daoimap) { | ||
1080 | hw_write_20kx(hw, AUDIO_IO_AIM+ctl->daoimap.idx*4, | ||
1081 | ctl->daoimap.aim); | ||
1082 | ctl->dirty.bf.daoimap = 0; | ||
1083 | } | ||
1084 | |||
1085 | return 0; | ||
1086 | } | ||
1087 | |||
1088 | static int daio_mgr_get_ctrl_blk(struct hw *hw, void **rblk) | ||
1089 | { | ||
1090 | struct daio_mgr_ctrl_blk *blk; | ||
1091 | int i; | ||
1092 | |||
1093 | *rblk = NULL; | ||
1094 | blk = kzalloc(sizeof(*blk), GFP_KERNEL); | ||
1095 | if (NULL == blk) | ||
1096 | return -ENOMEM; | ||
1097 | |||
1098 | for (i = 0; i < 8; i++) { | ||
1099 | blk->txctl[i] = hw_read_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i)); | ||
1100 | blk->rxctl[i] = hw_read_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i)); | ||
1101 | } | ||
1102 | |||
1103 | *rblk = blk; | ||
1104 | |||
1105 | return 0; | ||
1106 | } | ||
1107 | |||
1108 | static int daio_mgr_put_ctrl_blk(void *blk) | ||
1109 | { | ||
1110 | kfree(blk); | ||
1111 | |||
1112 | return 0; | ||
1113 | } | ||
1114 | |||
1115 | /* Card hardware initialization block */ | ||
1116 | struct dac_conf { | ||
1117 | unsigned int msr; /* master sample rate in rsrs */ | ||
1118 | }; | ||
1119 | |||
1120 | struct adc_conf { | ||
1121 | unsigned int msr; /* master sample rate in rsrs */ | ||
1122 | unsigned char input; /* the input source of ADC */ | ||
1123 | unsigned char mic20db; /* boost mic by 20db if input is microphone */ | ||
1124 | }; | ||
1125 | |||
1126 | struct daio_conf { | ||
1127 | unsigned int msr; /* master sample rate in rsrs */ | ||
1128 | }; | ||
1129 | |||
1130 | struct trn_conf { | ||
1131 | unsigned long vm_pgt_phys; | ||
1132 | }; | ||
1133 | |||
1134 | static int hw_daio_init(struct hw *hw, const struct daio_conf *info) | ||
1135 | { | ||
1136 | u32 data; | ||
1137 | int i; | ||
1138 | |||
1139 | /* Program I2S with proper sample rate and enable the correct I2S | ||
1140 | * channel. ED(0/8/16/24): Enable all I2S/I2X master clock output */ | ||
1141 | if (1 == info->msr) { | ||
1142 | hw_write_20kx(hw, AUDIO_IO_MCLK, 0x01010101); | ||
1143 | hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x01010101); | ||
1144 | hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); | ||
1145 | } else if (2 == info->msr) { | ||
1146 | hw_write_20kx(hw, AUDIO_IO_MCLK, 0x11111111); | ||
1147 | /* Specify all playing 96khz | ||
1148 | * EA [0] - Enabled | ||
1149 | * RTA [4:5] - 96kHz | ||
1150 | * EB [8] - Enabled | ||
1151 | * RTB [12:13] - 96kHz | ||
1152 | * EC [16] - Enabled | ||
1153 | * RTC [20:21] - 96kHz | ||
1154 | * ED [24] - Enabled | ||
1155 | * RTD [28:29] - 96kHz */ | ||
1156 | hw_write_20kx(hw, AUDIO_IO_TX_BLRCLK, 0x11111111); | ||
1157 | hw_write_20kx(hw, AUDIO_IO_RX_BLRCLK, 0); | ||
1158 | } else { | ||
1159 | printk(KERN_ALERT "ctxfi: ERROR!!! Invalid sampling rate!!!\n"); | ||
1160 | return -EINVAL; | ||
1161 | } | ||
1162 | |||
1163 | for (i = 0; i < 8; i++) { | ||
1164 | if (i <= 3) { | ||
1165 | /* 1st 3 channels are SPDIFs (SB0960) */ | ||
1166 | if (i == 3) | ||
1167 | data = 0x1001001; | ||
1168 | else | ||
1169 | data = 0x1000001; | ||
1170 | |||
1171 | hw_write_20kx(hw, (AUDIO_IO_TX_CTL+(0x40*i)), data); | ||
1172 | hw_write_20kx(hw, (AUDIO_IO_RX_CTL+(0x40*i)), data); | ||
1173 | |||
1174 | /* Initialize the SPDIF Out Channel status registers. | ||
1175 | * The value specified here is based on the typical | ||
1176 | * values provided in the specification, namely: Clock | ||
1177 | * Accuracy of 1000ppm, Sample Rate of 48KHz, | ||
1178 | * unspecified source number, Generation status = 1, | ||
1179 | * Category code = 0x12 (Digital Signal Mixer), | ||
1180 | * Mode = 0, Emph = 0, Copy Permitted, AN = 0 | ||
1181 | * (indicating that we're transmitting digital audio, | ||
1182 | * and the Professional Use bit is 0. */ | ||
1183 | |||
1184 | hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_L+(0x40*i), | ||
1185 | 0x02109204); /* Default to 48kHz */ | ||
1186 | |||
1187 | hw_write_20kx(hw, AUDIO_IO_TX_CSTAT_H+(0x40*i), 0x0B); | ||
1188 | } else { | ||
1189 | /* Next 5 channels are I2S (SB0960) */ | ||
1190 | data = 0x11; | ||
1191 | hw_write_20kx(hw, AUDIO_IO_RX_CTL+(0x40*i), data); | ||
1192 | if (2 == info->msr) { | ||
1193 | /* Four channels per sample period */ | ||
1194 | data |= 0x1000; | ||
1195 | } | ||
1196 | hw_write_20kx(hw, AUDIO_IO_TX_CTL+(0x40*i), data); | ||
1197 | } | ||
1198 | } | ||
1199 | |||
1200 | return 0; | ||
1201 | } | ||
1202 | |||
1203 | /* TRANSPORT operations */ | ||
1204 | static int hw_trn_init(struct hw *hw, const struct trn_conf *info) | ||
1205 | { | ||
1206 | u32 vmctl, data; | ||
1207 | u32 ptp_phys_low, ptp_phys_high; | ||
1208 | int i; | ||
1209 | |||
1210 | /* Set up device page table */ | ||
1211 | if ((~0UL) == info->vm_pgt_phys) { | ||
1212 | printk(KERN_ALERT "ctxfi: " | ||
1213 | "Wrong device page table page address!!!\n"); | ||
1214 | return -1; | ||
1215 | } | ||
1216 | |||
1217 | vmctl = 0x80000C0F; /* 32-bit, 4k-size page */ | ||
1218 | ptp_phys_low = (u32)info->vm_pgt_phys; | ||
1219 | ptp_phys_high = upper_32_bits(info->vm_pgt_phys); | ||
1220 | if (sizeof(void *) == 8) /* 64bit address */ | ||
1221 | vmctl |= (3 << 8); | ||
1222 | /* Write page table physical address to all PTPAL registers */ | ||
1223 | for (i = 0; i < 64; i++) { | ||
1224 | hw_write_20kx(hw, VMEM_PTPAL+(16*i), ptp_phys_low); | ||
1225 | hw_write_20kx(hw, VMEM_PTPAH+(16*i), ptp_phys_high); | ||
1226 | } | ||
1227 | /* Enable virtual memory transfer */ | ||
1228 | hw_write_20kx(hw, VMEM_CTL, vmctl); | ||
1229 | /* Enable transport bus master and queueing of request */ | ||
1230 | hw_write_20kx(hw, TRANSPORT_CTL, 0x03); | ||
1231 | hw_write_20kx(hw, TRANSPORT_INT, 0x200c01); | ||
1232 | /* Enable transport ring */ | ||
1233 | data = hw_read_20kx(hw, TRANSPORT_ENB); | ||
1234 | hw_write_20kx(hw, TRANSPORT_ENB, (data | 0x03)); | ||
1235 | |||
1236 | return 0; | ||
1237 | } | ||
1238 | |||
1239 | /* Card initialization */ | ||
1240 | #define GCTL_AIE 0x00000001 | ||
1241 | #define GCTL_UAA 0x00000002 | ||
1242 | #define GCTL_DPC 0x00000004 | ||
1243 | #define GCTL_DBP 0x00000008 | ||
1244 | #define GCTL_ABP 0x00000010 | ||
1245 | #define GCTL_TBP 0x00000020 | ||
1246 | #define GCTL_SBP 0x00000040 | ||
1247 | #define GCTL_FBP 0x00000080 | ||
1248 | #define GCTL_ME 0x00000100 | ||
1249 | #define GCTL_AID 0x00001000 | ||
1250 | |||
1251 | #define PLLCTL_SRC 0x00000007 | ||
1252 | #define PLLCTL_SPE 0x00000008 | ||
1253 | #define PLLCTL_RD 0x000000F0 | ||
1254 | #define PLLCTL_FD 0x0001FF00 | ||
1255 | #define PLLCTL_OD 0x00060000 | ||
1256 | #define PLLCTL_B 0x00080000 | ||
1257 | #define PLLCTL_AS 0x00100000 | ||
1258 | #define PLLCTL_LF 0x03E00000 | ||
1259 | #define PLLCTL_SPS 0x1C000000 | ||
1260 | #define PLLCTL_AD 0x60000000 | ||
1261 | |||
1262 | #define PLLSTAT_CCS 0x00000007 | ||
1263 | #define PLLSTAT_SPL 0x00000008 | ||
1264 | #define PLLSTAT_CRD 0x000000F0 | ||
1265 | #define PLLSTAT_CFD 0x0001FF00 | ||
1266 | #define PLLSTAT_SL 0x00020000 | ||
1267 | #define PLLSTAT_FAS 0x00040000 | ||
1268 | #define PLLSTAT_B 0x00080000 | ||
1269 | #define PLLSTAT_PD 0x00100000 | ||
1270 | #define PLLSTAT_OCA 0x00200000 | ||
1271 | #define PLLSTAT_NCA 0x00400000 | ||
1272 | |||
1273 | static int hw_pll_init(struct hw *hw, unsigned int rsr) | ||
1274 | { | ||
1275 | unsigned int pllenb; | ||
1276 | unsigned int pllctl; | ||
1277 | unsigned int pllstat; | ||
1278 | int i; | ||
1279 | |||
1280 | pllenb = 0xB; | ||
1281 | hw_write_20kx(hw, PLL_ENB, pllenb); | ||
1282 | pllctl = 0x20D00000; | ||
1283 | set_field(&pllctl, PLLCTL_FD, 16 - 4); | ||
1284 | hw_write_20kx(hw, PLL_CTL, pllctl); | ||
1285 | mdelay(40); | ||
1286 | pllctl = hw_read_20kx(hw, PLL_CTL); | ||
1287 | set_field(&pllctl, PLLCTL_B, 0); | ||
1288 | if (48000 == rsr) { | ||
1289 | set_field(&pllctl, PLLCTL_FD, 16 - 2); | ||
1290 | set_field(&pllctl, PLLCTL_RD, 1 - 1); | ||
1291 | } else { /* 44100 */ | ||
1292 | set_field(&pllctl, PLLCTL_FD, 147 - 2); | ||
1293 | set_field(&pllctl, PLLCTL_RD, 10 - 1); | ||
1294 | } | ||
1295 | hw_write_20kx(hw, PLL_CTL, pllctl); | ||
1296 | mdelay(40); | ||
1297 | for (i = 0; i < 1000; i++) { | ||
1298 | pllstat = hw_read_20kx(hw, PLL_STAT); | ||
1299 | if (get_field(pllstat, PLLSTAT_PD)) | ||
1300 | continue; | ||
1301 | |||
1302 | if (get_field(pllstat, PLLSTAT_B) != | ||
1303 | get_field(pllctl, PLLCTL_B)) | ||
1304 | continue; | ||
1305 | |||
1306 | if (get_field(pllstat, PLLSTAT_CCS) != | ||
1307 | get_field(pllctl, PLLCTL_SRC)) | ||
1308 | continue; | ||
1309 | |||
1310 | if (get_field(pllstat, PLLSTAT_CRD) != | ||
1311 | get_field(pllctl, PLLCTL_RD)) | ||
1312 | continue; | ||
1313 | |||
1314 | if (get_field(pllstat, PLLSTAT_CFD) != | ||
1315 | get_field(pllctl, PLLCTL_FD)) | ||
1316 | continue; | ||
1317 | |||
1318 | break; | ||
1319 | } | ||
1320 | if (i >= 1000) { | ||
1321 | printk(KERN_ALERT "ctxfi: PLL initialization failed!!!\n"); | ||
1322 | return -EBUSY; | ||
1323 | } | ||
1324 | |||
1325 | return 0; | ||
1326 | } | ||
1327 | |||
1328 | static int hw_auto_init(struct hw *hw) | ||
1329 | { | ||
1330 | unsigned int gctl; | ||
1331 | int i; | ||
1332 | |||
1333 | gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); | ||
1334 | set_field(&gctl, GCTL_AIE, 0); | ||
1335 | hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); | ||
1336 | set_field(&gctl, GCTL_AIE, 1); | ||
1337 | hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); | ||
1338 | mdelay(10); | ||
1339 | for (i = 0; i < 400000; i++) { | ||
1340 | gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); | ||
1341 | if (get_field(gctl, GCTL_AID)) | ||
1342 | break; | ||
1343 | } | ||
1344 | if (!get_field(gctl, GCTL_AID)) { | ||
1345 | printk(KERN_ALERT "ctxfi: Card Auto-init failed!!!\n"); | ||
1346 | return -EBUSY; | ||
1347 | } | ||
1348 | |||
1349 | return 0; | ||
1350 | } | ||
1351 | |||
1352 | /* DAC operations */ | ||
1353 | |||
1354 | #define CS4382_MC1 0x1 | ||
1355 | #define CS4382_MC2 0x2 | ||
1356 | #define CS4382_MC3 0x3 | ||
1357 | #define CS4382_FC 0x4 | ||
1358 | #define CS4382_IC 0x5 | ||
1359 | #define CS4382_XC1 0x6 | ||
1360 | #define CS4382_VCA1 0x7 | ||
1361 | #define CS4382_VCB1 0x8 | ||
1362 | #define CS4382_XC2 0x9 | ||
1363 | #define CS4382_VCA2 0xA | ||
1364 | #define CS4382_VCB2 0xB | ||
1365 | #define CS4382_XC3 0xC | ||
1366 | #define CS4382_VCA3 0xD | ||
1367 | #define CS4382_VCB3 0xE | ||
1368 | #define CS4382_XC4 0xF | ||
1369 | #define CS4382_VCA4 0x10 | ||
1370 | #define CS4382_VCB4 0x11 | ||
1371 | #define CS4382_CREV 0x12 | ||
1372 | |||
1373 | /* I2C status */ | ||
1374 | #define STATE_LOCKED 0x00 | ||
1375 | #define STATE_UNLOCKED 0xAA | ||
1376 | #define DATA_READY 0x800000 /* Used with I2C_IF_STATUS */ | ||
1377 | #define DATA_ABORT 0x10000 /* Used with I2C_IF_STATUS */ | ||
1378 | |||
1379 | #define I2C_STATUS_DCM 0x00000001 | ||
1380 | #define I2C_STATUS_BC 0x00000006 | ||
1381 | #define I2C_STATUS_APD 0x00000008 | ||
1382 | #define I2C_STATUS_AB 0x00010000 | ||
1383 | #define I2C_STATUS_DR 0x00800000 | ||
1384 | |||
1385 | #define I2C_ADDRESS_PTAD 0x0000FFFF | ||
1386 | #define I2C_ADDRESS_SLAD 0x007F0000 | ||
1387 | |||
1388 | struct regs_cs4382 { | ||
1389 | u32 mode_control_1; | ||
1390 | u32 mode_control_2; | ||
1391 | u32 mode_control_3; | ||
1392 | |||
1393 | u32 filter_control; | ||
1394 | u32 invert_control; | ||
1395 | |||
1396 | u32 mix_control_P1; | ||
1397 | u32 vol_control_A1; | ||
1398 | u32 vol_control_B1; | ||
1399 | |||
1400 | u32 mix_control_P2; | ||
1401 | u32 vol_control_A2; | ||
1402 | u32 vol_control_B2; | ||
1403 | |||
1404 | u32 mix_control_P3; | ||
1405 | u32 vol_control_A3; | ||
1406 | u32 vol_control_B3; | ||
1407 | |||
1408 | u32 mix_control_P4; | ||
1409 | u32 vol_control_A4; | ||
1410 | u32 vol_control_B4; | ||
1411 | }; | ||
1412 | |||
1413 | static int hw20k2_i2c_unlock_full_access(struct hw *hw) | ||
1414 | { | ||
1415 | u8 UnlockKeySequence_FLASH_FULLACCESS_MODE[2] = {0xB3, 0xD4}; | ||
1416 | |||
1417 | /* Send keys for forced BIOS mode */ | ||
1418 | hw_write_20kx(hw, I2C_IF_WLOCK, | ||
1419 | UnlockKeySequence_FLASH_FULLACCESS_MODE[0]); | ||
1420 | hw_write_20kx(hw, I2C_IF_WLOCK, | ||
1421 | UnlockKeySequence_FLASH_FULLACCESS_MODE[1]); | ||
1422 | /* Check whether the chip is unlocked */ | ||
1423 | if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_UNLOCKED) | ||
1424 | return 0; | ||
1425 | |||
1426 | return -1; | ||
1427 | } | ||
1428 | |||
1429 | static int hw20k2_i2c_lock_chip(struct hw *hw) | ||
1430 | { | ||
1431 | /* Write twice */ | ||
1432 | hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED); | ||
1433 | hw_write_20kx(hw, I2C_IF_WLOCK, STATE_LOCKED); | ||
1434 | if (hw_read_20kx(hw, I2C_IF_WLOCK) == STATE_LOCKED) | ||
1435 | return 0; | ||
1436 | |||
1437 | return -1; | ||
1438 | } | ||
1439 | |||
1440 | static int hw20k2_i2c_init(struct hw *hw, u8 dev_id, u8 addr_size, u8 data_size) | ||
1441 | { | ||
1442 | struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; | ||
1443 | int err; | ||
1444 | unsigned int i2c_status; | ||
1445 | unsigned int i2c_addr; | ||
1446 | |||
1447 | err = hw20k2_i2c_unlock_full_access(hw); | ||
1448 | if (err < 0) | ||
1449 | return err; | ||
1450 | |||
1451 | hw20k2->addr_size = addr_size; | ||
1452 | hw20k2->data_size = data_size; | ||
1453 | hw20k2->dev_id = dev_id; | ||
1454 | |||
1455 | i2c_addr = 0; | ||
1456 | set_field(&i2c_addr, I2C_ADDRESS_SLAD, dev_id); | ||
1457 | |||
1458 | hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr); | ||
1459 | |||
1460 | i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); | ||
1461 | |||
1462 | set_field(&i2c_status, I2C_STATUS_DCM, 1); /* Direct control mode */ | ||
1463 | |||
1464 | hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); | ||
1465 | |||
1466 | return 0; | ||
1467 | } | ||
1468 | |||
1469 | static int hw20k2_i2c_uninit(struct hw *hw) | ||
1470 | { | ||
1471 | unsigned int i2c_status; | ||
1472 | unsigned int i2c_addr; | ||
1473 | |||
1474 | i2c_addr = 0; | ||
1475 | set_field(&i2c_addr, I2C_ADDRESS_SLAD, 0x57); /* I2C id */ | ||
1476 | |||
1477 | hw_write_20kx(hw, I2C_IF_ADDRESS, i2c_addr); | ||
1478 | |||
1479 | i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); | ||
1480 | |||
1481 | set_field(&i2c_status, I2C_STATUS_DCM, 0); /* I2C mode */ | ||
1482 | |||
1483 | hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); | ||
1484 | |||
1485 | return hw20k2_i2c_lock_chip(hw); | ||
1486 | } | ||
1487 | |||
1488 | static int hw20k2_i2c_wait_data_ready(struct hw *hw) | ||
1489 | { | ||
1490 | int i = 0x400000; | ||
1491 | unsigned int ret; | ||
1492 | |||
1493 | do { | ||
1494 | ret = hw_read_20kx(hw, I2C_IF_STATUS); | ||
1495 | } while ((!(ret & DATA_READY)) && --i); | ||
1496 | |||
1497 | return i; | ||
1498 | } | ||
1499 | |||
1500 | static int hw20k2_i2c_read(struct hw *hw, u16 addr, u32 *datap) | ||
1501 | { | ||
1502 | struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; | ||
1503 | unsigned int i2c_status; | ||
1504 | |||
1505 | i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); | ||
1506 | set_field(&i2c_status, I2C_STATUS_BC, | ||
1507 | (4 == hw20k2->addr_size) ? 0 : hw20k2->addr_size); | ||
1508 | hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); | ||
1509 | if (!hw20k2_i2c_wait_data_ready(hw)) | ||
1510 | return -1; | ||
1511 | |||
1512 | hw_write_20kx(hw, I2C_IF_WDATA, addr); | ||
1513 | if (!hw20k2_i2c_wait_data_ready(hw)) | ||
1514 | return -1; | ||
1515 | |||
1516 | /* Force a read operation */ | ||
1517 | hw_write_20kx(hw, I2C_IF_RDATA, 0); | ||
1518 | if (!hw20k2_i2c_wait_data_ready(hw)) | ||
1519 | return -1; | ||
1520 | |||
1521 | *datap = hw_read_20kx(hw, I2C_IF_RDATA); | ||
1522 | |||
1523 | return 0; | ||
1524 | } | ||
1525 | |||
1526 | static int hw20k2_i2c_write(struct hw *hw, u16 addr, u32 data) | ||
1527 | { | ||
1528 | struct hw20k2 *hw20k2 = (struct hw20k2 *)hw; | ||
1529 | unsigned int i2c_data = (data << (hw20k2->addr_size * 8)) | addr; | ||
1530 | unsigned int i2c_status; | ||
1531 | |||
1532 | i2c_status = hw_read_20kx(hw, I2C_IF_STATUS); | ||
1533 | |||
1534 | set_field(&i2c_status, I2C_STATUS_BC, | ||
1535 | (4 == (hw20k2->addr_size + hw20k2->data_size)) ? | ||
1536 | 0 : (hw20k2->addr_size + hw20k2->data_size)); | ||
1537 | |||
1538 | hw_write_20kx(hw, I2C_IF_STATUS, i2c_status); | ||
1539 | hw20k2_i2c_wait_data_ready(hw); | ||
1540 | /* Dummy write to trigger the write oprtation */ | ||
1541 | hw_write_20kx(hw, I2C_IF_WDATA, 0); | ||
1542 | hw20k2_i2c_wait_data_ready(hw); | ||
1543 | |||
1544 | /* This is the real data */ | ||
1545 | hw_write_20kx(hw, I2C_IF_WDATA, i2c_data); | ||
1546 | hw20k2_i2c_wait_data_ready(hw); | ||
1547 | |||
1548 | return 0; | ||
1549 | } | ||
1550 | |||
1551 | static int hw_dac_init(struct hw *hw, const struct dac_conf *info) | ||
1552 | { | ||
1553 | int err; | ||
1554 | u32 data; | ||
1555 | int i; | ||
1556 | struct regs_cs4382 cs_read = {0}; | ||
1557 | struct regs_cs4382 cs_def = { | ||
1558 | 0x00000001, /* Mode Control 1 */ | ||
1559 | 0x00000000, /* Mode Control 2 */ | ||
1560 | 0x00000084, /* Mode Control 3 */ | ||
1561 | 0x00000000, /* Filter Control */ | ||
1562 | 0x00000000, /* Invert Control */ | ||
1563 | 0x00000024, /* Mixing Control Pair 1 */ | ||
1564 | 0x00000000, /* Vol Control A1 */ | ||
1565 | 0x00000000, /* Vol Control B1 */ | ||
1566 | 0x00000024, /* Mixing Control Pair 2 */ | ||
1567 | 0x00000000, /* Vol Control A2 */ | ||
1568 | 0x00000000, /* Vol Control B2 */ | ||
1569 | 0x00000024, /* Mixing Control Pair 3 */ | ||
1570 | 0x00000000, /* Vol Control A3 */ | ||
1571 | 0x00000000, /* Vol Control B3 */ | ||
1572 | 0x00000024, /* Mixing Control Pair 4 */ | ||
1573 | 0x00000000, /* Vol Control A4 */ | ||
1574 | 0x00000000 /* Vol Control B4 */ | ||
1575 | }; | ||
1576 | |||
1577 | /* Set DAC reset bit as output */ | ||
1578 | data = hw_read_20kx(hw, GPIO_CTRL); | ||
1579 | data |= 0x02; | ||
1580 | hw_write_20kx(hw, GPIO_CTRL, data); | ||
1581 | |||
1582 | err = hw20k2_i2c_init(hw, 0x18, 1, 1); | ||
1583 | if (err < 0) | ||
1584 | goto End; | ||
1585 | |||
1586 | for (i = 0; i < 2; i++) { | ||
1587 | /* Reset DAC twice just in-case the chip | ||
1588 | * didn't initialized properly */ | ||
1589 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1590 | /* GPIO data bit 1 */ | ||
1591 | data &= 0xFFFFFFFD; | ||
1592 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1593 | mdelay(10); | ||
1594 | data |= 0x2; | ||
1595 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1596 | mdelay(50); | ||
1597 | |||
1598 | /* Reset the 2nd time */ | ||
1599 | data &= 0xFFFFFFFD; | ||
1600 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1601 | mdelay(10); | ||
1602 | data |= 0x2; | ||
1603 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1604 | mdelay(50); | ||
1605 | |||
1606 | if (hw20k2_i2c_read(hw, CS4382_MC1, &cs_read.mode_control_1)) | ||
1607 | continue; | ||
1608 | |||
1609 | if (hw20k2_i2c_read(hw, CS4382_MC2, &cs_read.mode_control_2)) | ||
1610 | continue; | ||
1611 | |||
1612 | if (hw20k2_i2c_read(hw, CS4382_MC3, &cs_read.mode_control_3)) | ||
1613 | continue; | ||
1614 | |||
1615 | if (hw20k2_i2c_read(hw, CS4382_FC, &cs_read.filter_control)) | ||
1616 | continue; | ||
1617 | |||
1618 | if (hw20k2_i2c_read(hw, CS4382_IC, &cs_read.invert_control)) | ||
1619 | continue; | ||
1620 | |||
1621 | if (hw20k2_i2c_read(hw, CS4382_XC1, &cs_read.mix_control_P1)) | ||
1622 | continue; | ||
1623 | |||
1624 | if (hw20k2_i2c_read(hw, CS4382_VCA1, &cs_read.vol_control_A1)) | ||
1625 | continue; | ||
1626 | |||
1627 | if (hw20k2_i2c_read(hw, CS4382_VCB1, &cs_read.vol_control_B1)) | ||
1628 | continue; | ||
1629 | |||
1630 | if (hw20k2_i2c_read(hw, CS4382_XC2, &cs_read.mix_control_P2)) | ||
1631 | continue; | ||
1632 | |||
1633 | if (hw20k2_i2c_read(hw, CS4382_VCA2, &cs_read.vol_control_A2)) | ||
1634 | continue; | ||
1635 | |||
1636 | if (hw20k2_i2c_read(hw, CS4382_VCB2, &cs_read.vol_control_B2)) | ||
1637 | continue; | ||
1638 | |||
1639 | if (hw20k2_i2c_read(hw, CS4382_XC3, &cs_read.mix_control_P3)) | ||
1640 | continue; | ||
1641 | |||
1642 | if (hw20k2_i2c_read(hw, CS4382_VCA3, &cs_read.vol_control_A3)) | ||
1643 | continue; | ||
1644 | |||
1645 | if (hw20k2_i2c_read(hw, CS4382_VCB3, &cs_read.vol_control_B3)) | ||
1646 | continue; | ||
1647 | |||
1648 | if (hw20k2_i2c_read(hw, CS4382_XC4, &cs_read.mix_control_P4)) | ||
1649 | continue; | ||
1650 | |||
1651 | if (hw20k2_i2c_read(hw, CS4382_VCA4, &cs_read.vol_control_A4)) | ||
1652 | continue; | ||
1653 | |||
1654 | if (hw20k2_i2c_read(hw, CS4382_VCB4, &cs_read.vol_control_B4)) | ||
1655 | continue; | ||
1656 | |||
1657 | if (memcmp(&cs_read, &cs_def, sizeof(cs_read))) | ||
1658 | continue; | ||
1659 | else | ||
1660 | break; | ||
1661 | } | ||
1662 | |||
1663 | if (i >= 2) | ||
1664 | goto End; | ||
1665 | |||
1666 | /* Note: Every I2C write must have some delay. | ||
1667 | * This is not a requirement but the delay works here... */ | ||
1668 | hw20k2_i2c_write(hw, CS4382_MC1, 0x80); | ||
1669 | hw20k2_i2c_write(hw, CS4382_MC2, 0x10); | ||
1670 | if (1 == info->msr) { | ||
1671 | hw20k2_i2c_write(hw, CS4382_XC1, 0x24); | ||
1672 | hw20k2_i2c_write(hw, CS4382_XC2, 0x24); | ||
1673 | hw20k2_i2c_write(hw, CS4382_XC3, 0x24); | ||
1674 | hw20k2_i2c_write(hw, CS4382_XC4, 0x24); | ||
1675 | } else if (2 == info->msr) { | ||
1676 | hw20k2_i2c_write(hw, CS4382_XC1, 0x25); | ||
1677 | hw20k2_i2c_write(hw, CS4382_XC2, 0x25); | ||
1678 | hw20k2_i2c_write(hw, CS4382_XC3, 0x25); | ||
1679 | hw20k2_i2c_write(hw, CS4382_XC4, 0x25); | ||
1680 | } else { | ||
1681 | hw20k2_i2c_write(hw, CS4382_XC1, 0x26); | ||
1682 | hw20k2_i2c_write(hw, CS4382_XC2, 0x26); | ||
1683 | hw20k2_i2c_write(hw, CS4382_XC3, 0x26); | ||
1684 | hw20k2_i2c_write(hw, CS4382_XC4, 0x26); | ||
1685 | } | ||
1686 | |||
1687 | return 0; | ||
1688 | End: | ||
1689 | |||
1690 | hw20k2_i2c_uninit(hw); | ||
1691 | return -1; | ||
1692 | } | ||
1693 | |||
1694 | /* ADC operations */ | ||
1695 | #define MAKE_WM8775_ADDR(addr, data) (u32)(((addr<<1)&0xFE)|((data>>8)&0x1)) | ||
1696 | #define MAKE_WM8775_DATA(data) (u32)(data&0xFF) | ||
1697 | |||
1698 | #define WM8775_IC 0x0B | ||
1699 | #define WM8775_MMC 0x0C | ||
1700 | #define WM8775_AADCL 0x0E | ||
1701 | #define WM8775_AADCR 0x0F | ||
1702 | #define WM8775_ADCMC 0x15 | ||
1703 | #define WM8775_RESET 0x17 | ||
1704 | |||
1705 | static int hw_is_adc_input_selected(struct hw *hw, enum ADCSRC type) | ||
1706 | { | ||
1707 | u32 data; | ||
1708 | |||
1709 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1710 | switch (type) { | ||
1711 | case ADC_MICIN: | ||
1712 | data = (data & (0x1 << 14)) ? 1 : 0; | ||
1713 | break; | ||
1714 | case ADC_LINEIN: | ||
1715 | data = (data & (0x1 << 14)) ? 0 : 1; | ||
1716 | break; | ||
1717 | default: | ||
1718 | data = 0; | ||
1719 | } | ||
1720 | return data; | ||
1721 | } | ||
1722 | |||
1723 | static int hw_adc_input_select(struct hw *hw, enum ADCSRC type) | ||
1724 | { | ||
1725 | u32 data; | ||
1726 | |||
1727 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1728 | switch (type) { | ||
1729 | case ADC_MICIN: | ||
1730 | data |= (0x1 << 14); | ||
1731 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1732 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), | ||
1733 | MAKE_WM8775_DATA(0x101)); /* Mic-in */ | ||
1734 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7), | ||
1735 | MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ | ||
1736 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7), | ||
1737 | MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ | ||
1738 | break; | ||
1739 | case ADC_LINEIN: | ||
1740 | data &= ~(0x1 << 14); | ||
1741 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1742 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), | ||
1743 | MAKE_WM8775_DATA(0x102)); /* Line-in */ | ||
1744 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), | ||
1745 | MAKE_WM8775_DATA(0xCF)); /* No boost */ | ||
1746 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), | ||
1747 | MAKE_WM8775_DATA(0xCF)); /* No boost */ | ||
1748 | break; | ||
1749 | default: | ||
1750 | break; | ||
1751 | } | ||
1752 | |||
1753 | return 0; | ||
1754 | } | ||
1755 | |||
1756 | static int hw_adc_init(struct hw *hw, const struct adc_conf *info) | ||
1757 | { | ||
1758 | int err; | ||
1759 | u32 mux = 2, data, ctl; | ||
1760 | |||
1761 | /* Set ADC reset bit as output */ | ||
1762 | data = hw_read_20kx(hw, GPIO_CTRL); | ||
1763 | data |= (0x1 << 15); | ||
1764 | hw_write_20kx(hw, GPIO_CTRL, data); | ||
1765 | |||
1766 | /* Initialize I2C */ | ||
1767 | err = hw20k2_i2c_init(hw, 0x1A, 1, 1); | ||
1768 | if (err < 0) { | ||
1769 | printk(KERN_ALERT "ctxfi: Failure to acquire I2C!!!\n"); | ||
1770 | goto error; | ||
1771 | } | ||
1772 | |||
1773 | /* Make ADC in normal operation */ | ||
1774 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1775 | data &= ~(0x1 << 15); | ||
1776 | mdelay(10); | ||
1777 | data |= (0x1 << 15); | ||
1778 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1779 | mdelay(50); | ||
1780 | |||
1781 | /* Set the master mode (256fs) */ | ||
1782 | if (1 == info->msr) { | ||
1783 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x02), | ||
1784 | MAKE_WM8775_DATA(0x02)); | ||
1785 | } else if (2 == info->msr) { | ||
1786 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_MMC, 0x0A), | ||
1787 | MAKE_WM8775_DATA(0x0A)); | ||
1788 | } else { | ||
1789 | printk(KERN_ALERT "ctxfi: Invalid master sampling " | ||
1790 | "rate (msr %d)!!!\n", info->msr); | ||
1791 | err = -EINVAL; | ||
1792 | goto error; | ||
1793 | } | ||
1794 | |||
1795 | /* Configure GPIO bit 14 change to line-in/mic-in */ | ||
1796 | ctl = hw_read_20kx(hw, GPIO_CTRL); | ||
1797 | ctl |= 0x1 << 14; | ||
1798 | hw_write_20kx(hw, GPIO_CTRL, ctl); | ||
1799 | |||
1800 | /* Check using Mic-in or Line-in */ | ||
1801 | data = hw_read_20kx(hw, GPIO_DATA); | ||
1802 | |||
1803 | if (mux == 1) { | ||
1804 | /* Configures GPIO data to select Mic-in */ | ||
1805 | data |= 0x1 << 14; | ||
1806 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1807 | |||
1808 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x101), | ||
1809 | MAKE_WM8775_DATA(0x101)); /* Mic-in */ | ||
1810 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xE7), | ||
1811 | MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ | ||
1812 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xE7), | ||
1813 | MAKE_WM8775_DATA(0xE7)); /* +12dB boost */ | ||
1814 | } else if (mux == 2) { | ||
1815 | /* Configures GPIO data to select Line-in */ | ||
1816 | data &= ~(0x1 << 14); | ||
1817 | hw_write_20kx(hw, GPIO_DATA, data); | ||
1818 | |||
1819 | /* Setup ADC */ | ||
1820 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_ADCMC, 0x102), | ||
1821 | MAKE_WM8775_DATA(0x102)); /* Line-in */ | ||
1822 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCL, 0xCF), | ||
1823 | MAKE_WM8775_DATA(0xCF)); /* No boost */ | ||
1824 | hw20k2_i2c_write(hw, MAKE_WM8775_ADDR(WM8775_AADCR, 0xCF), | ||
1825 | MAKE_WM8775_DATA(0xCF)); /* No boost */ | ||
1826 | } else { | ||
1827 | printk(KERN_ALERT "ctxfi: ERROR!!! Invalid input mux!!!\n"); | ||
1828 | err = -EINVAL; | ||
1829 | goto error; | ||
1830 | } | ||
1831 | |||
1832 | return 0; | ||
1833 | |||
1834 | error: | ||
1835 | hw20k2_i2c_uninit(hw); | ||
1836 | return err; | ||
1837 | } | ||
1838 | |||
1839 | static int hw_have_digit_io_switch(struct hw *hw) | ||
1840 | { | ||
1841 | return 0; | ||
1842 | } | ||
1843 | |||
1844 | static int hw_card_start(struct hw *hw) | ||
1845 | { | ||
1846 | int err = 0; | ||
1847 | struct pci_dev *pci = hw->pci; | ||
1848 | unsigned int gctl; | ||
1849 | |||
1850 | err = pci_enable_device(pci); | ||
1851 | if (err < 0) | ||
1852 | return err; | ||
1853 | |||
1854 | /* Set DMA transfer mask */ | ||
1855 | if (pci_set_dma_mask(pci, CT_XFI_DMA_MASK) < 0 || | ||
1856 | pci_set_consistent_dma_mask(pci, CT_XFI_DMA_MASK) < 0) { | ||
1857 | printk(KERN_ERR "ctxfi: architecture does not support PCI " | ||
1858 | "busmaster DMA with mask 0x%llx\n", CT_XFI_DMA_MASK); | ||
1859 | err = -ENXIO; | ||
1860 | goto error1; | ||
1861 | } | ||
1862 | |||
1863 | err = pci_request_regions(pci, "XFi"); | ||
1864 | if (err < 0) | ||
1865 | goto error1; | ||
1866 | |||
1867 | hw->io_base = pci_resource_start(hw->pci, 2); | ||
1868 | hw->mem_base = (unsigned long)ioremap(hw->io_base, | ||
1869 | pci_resource_len(hw->pci, 2)); | ||
1870 | if (NULL == (void *)hw->mem_base) { | ||
1871 | err = -ENOENT; | ||
1872 | goto error2; | ||
1873 | } | ||
1874 | |||
1875 | /* Switch to 20k2 mode from UAA mode. */ | ||
1876 | gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); | ||
1877 | set_field(&gctl, GCTL_UAA, 0); | ||
1878 | hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); | ||
1879 | |||
1880 | /*if ((err = request_irq(pci->irq, ct_atc_interrupt, IRQF_SHARED, | ||
1881 | atc->chip_details->nm_card, hw))) { | ||
1882 | goto error3; | ||
1883 | } | ||
1884 | hw->irq = pci->irq; | ||
1885 | */ | ||
1886 | |||
1887 | pci_set_master(pci); | ||
1888 | |||
1889 | return 0; | ||
1890 | |||
1891 | /*error3: | ||
1892 | iounmap((void *)hw->mem_base); | ||
1893 | hw->mem_base = (unsigned long)NULL;*/ | ||
1894 | error2: | ||
1895 | pci_release_regions(pci); | ||
1896 | hw->io_base = 0; | ||
1897 | error1: | ||
1898 | pci_disable_device(pci); | ||
1899 | return err; | ||
1900 | } | ||
1901 | |||
1902 | static int hw_card_stop(struct hw *hw) | ||
1903 | { | ||
1904 | /* TODO: Disable interrupt and so on... */ | ||
1905 | return 0; | ||
1906 | } | ||
1907 | |||
1908 | static int hw_card_shutdown(struct hw *hw) | ||
1909 | { | ||
1910 | if (hw->irq >= 0) | ||
1911 | free_irq(hw->irq, hw); | ||
1912 | |||
1913 | hw->irq = -1; | ||
1914 | |||
1915 | if (NULL != ((void *)hw->mem_base)) | ||
1916 | iounmap((void *)hw->mem_base); | ||
1917 | |||
1918 | hw->mem_base = (unsigned long)NULL; | ||
1919 | |||
1920 | if (hw->io_base) | ||
1921 | pci_release_regions(hw->pci); | ||
1922 | |||
1923 | hw->io_base = 0; | ||
1924 | |||
1925 | pci_disable_device(hw->pci); | ||
1926 | |||
1927 | return 0; | ||
1928 | } | ||
1929 | |||
1930 | static int hw_card_init(struct hw *hw, struct card_conf *info) | ||
1931 | { | ||
1932 | int err; | ||
1933 | unsigned int gctl; | ||
1934 | u32 data = 0; | ||
1935 | struct dac_conf dac_info = {0}; | ||
1936 | struct adc_conf adc_info = {0}; | ||
1937 | struct daio_conf daio_info = {0}; | ||
1938 | struct trn_conf trn_info = {0}; | ||
1939 | |||
1940 | /* Get PCI io port/memory base address and | ||
1941 | * do 20kx core switch if needed. */ | ||
1942 | if (!hw->io_base) { | ||
1943 | err = hw_card_start(hw); | ||
1944 | if (err) | ||
1945 | return err; | ||
1946 | } | ||
1947 | |||
1948 | /* PLL init */ | ||
1949 | err = hw_pll_init(hw, info->rsr); | ||
1950 | if (err < 0) | ||
1951 | return err; | ||
1952 | |||
1953 | /* kick off auto-init */ | ||
1954 | err = hw_auto_init(hw); | ||
1955 | if (err < 0) | ||
1956 | return err; | ||
1957 | |||
1958 | gctl = hw_read_20kx(hw, GLOBAL_CNTL_GCTL); | ||
1959 | set_field(&gctl, GCTL_DBP, 1); | ||
1960 | set_field(&gctl, GCTL_TBP, 1); | ||
1961 | set_field(&gctl, GCTL_FBP, 1); | ||
1962 | set_field(&gctl, GCTL_DPC, 0); | ||
1963 | hw_write_20kx(hw, GLOBAL_CNTL_GCTL, gctl); | ||
1964 | |||
1965 | /* Reset all global pending interrupts */ | ||
1966 | hw_write_20kx(hw, INTERRUPT_GIE, 0); | ||
1967 | /* Reset all SRC pending interrupts */ | ||
1968 | hw_write_20kx(hw, SRC_IP, 0); | ||
1969 | |||
1970 | /* TODO: detect the card ID and configure GPIO accordingly. */ | ||
1971 | /* Configures GPIO (0xD802 0x98028) */ | ||
1972 | /*hw_write_20kx(hw, GPIO_CTRL, 0x7F07);*/ | ||
1973 | /* Configures GPIO (SB0880) */ | ||
1974 | /*hw_write_20kx(hw, GPIO_CTRL, 0xFF07);*/ | ||
1975 | hw_write_20kx(hw, GPIO_CTRL, 0xD802); | ||
1976 | |||
1977 | /* Enable audio ring */ | ||
1978 | hw_write_20kx(hw, MIXER_AR_ENABLE, 0x01); | ||
1979 | |||
1980 | trn_info.vm_pgt_phys = info->vm_pgt_phys; | ||
1981 | err = hw_trn_init(hw, &trn_info); | ||
1982 | if (err < 0) | ||
1983 | return err; | ||
1984 | |||
1985 | daio_info.msr = info->msr; | ||
1986 | err = hw_daio_init(hw, &daio_info); | ||
1987 | if (err < 0) | ||
1988 | return err; | ||
1989 | |||
1990 | dac_info.msr = info->msr; | ||
1991 | err = hw_dac_init(hw, &dac_info); | ||
1992 | if (err < 0) | ||
1993 | return err; | ||
1994 | |||
1995 | adc_info.msr = info->msr; | ||
1996 | adc_info.input = ADC_LINEIN; | ||
1997 | adc_info.mic20db = 0; | ||
1998 | err = hw_adc_init(hw, &adc_info); | ||
1999 | if (err < 0) | ||
2000 | return err; | ||
2001 | |||
2002 | data = hw_read_20kx(hw, SRC_MCTL); | ||
2003 | data |= 0x1; /* Enables input from the audio ring */ | ||
2004 | hw_write_20kx(hw, SRC_MCTL, data); | ||
2005 | |||
2006 | return 0; | ||
2007 | } | ||
2008 | |||
2009 | static u32 hw_read_20kx(struct hw *hw, u32 reg) | ||
2010 | { | ||
2011 | return readl((void *)(hw->mem_base + reg)); | ||
2012 | } | ||
2013 | |||
2014 | static void hw_write_20kx(struct hw *hw, u32 reg, u32 data) | ||
2015 | { | ||
2016 | writel(data, (void *)(hw->mem_base + reg)); | ||
2017 | } | ||
2018 | |||
2019 | static struct hw ct20k2_preset __devinitdata = { | ||
2020 | .irq = -1, | ||
2021 | |||
2022 | .card_init = hw_card_init, | ||
2023 | .card_stop = hw_card_stop, | ||
2024 | .pll_init = hw_pll_init, | ||
2025 | .is_adc_source_selected = hw_is_adc_input_selected, | ||
2026 | .select_adc_source = hw_adc_input_select, | ||
2027 | .have_digit_io_switch = hw_have_digit_io_switch, | ||
2028 | |||
2029 | .src_rsc_get_ctrl_blk = src_get_rsc_ctrl_blk, | ||
2030 | .src_rsc_put_ctrl_blk = src_put_rsc_ctrl_blk, | ||
2031 | .src_mgr_get_ctrl_blk = src_mgr_get_ctrl_blk, | ||
2032 | .src_mgr_put_ctrl_blk = src_mgr_put_ctrl_blk, | ||
2033 | .src_set_state = src_set_state, | ||
2034 | .src_set_bm = src_set_bm, | ||
2035 | .src_set_rsr = src_set_rsr, | ||
2036 | .src_set_sf = src_set_sf, | ||
2037 | .src_set_wr = src_set_wr, | ||
2038 | .src_set_pm = src_set_pm, | ||
2039 | .src_set_rom = src_set_rom, | ||
2040 | .src_set_vo = src_set_vo, | ||
2041 | .src_set_st = src_set_st, | ||
2042 | .src_set_ie = src_set_ie, | ||
2043 | .src_set_ilsz = src_set_ilsz, | ||
2044 | .src_set_bp = src_set_bp, | ||
2045 | .src_set_cisz = src_set_cisz, | ||
2046 | .src_set_ca = src_set_ca, | ||
2047 | .src_set_sa = src_set_sa, | ||
2048 | .src_set_la = src_set_la, | ||
2049 | .src_set_pitch = src_set_pitch, | ||
2050 | .src_set_dirty = src_set_dirty, | ||
2051 | .src_set_clear_zbufs = src_set_clear_zbufs, | ||
2052 | .src_set_dirty_all = src_set_dirty_all, | ||
2053 | .src_commit_write = src_commit_write, | ||
2054 | .src_get_ca = src_get_ca, | ||
2055 | .src_get_dirty = src_get_dirty, | ||
2056 | .src_dirty_conj_mask = src_dirty_conj_mask, | ||
2057 | .src_mgr_enbs_src = src_mgr_enbs_src, | ||
2058 | .src_mgr_enb_src = src_mgr_enb_src, | ||
2059 | .src_mgr_dsb_src = src_mgr_dsb_src, | ||
2060 | .src_mgr_commit_write = src_mgr_commit_write, | ||
2061 | |||
2062 | .srcimp_mgr_get_ctrl_blk = srcimp_mgr_get_ctrl_blk, | ||
2063 | .srcimp_mgr_put_ctrl_blk = srcimp_mgr_put_ctrl_blk, | ||
2064 | .srcimp_mgr_set_imaparc = srcimp_mgr_set_imaparc, | ||
2065 | .srcimp_mgr_set_imapuser = srcimp_mgr_set_imapuser, | ||
2066 | .srcimp_mgr_set_imapnxt = srcimp_mgr_set_imapnxt, | ||
2067 | .srcimp_mgr_set_imapaddr = srcimp_mgr_set_imapaddr, | ||
2068 | .srcimp_mgr_commit_write = srcimp_mgr_commit_write, | ||
2069 | |||
2070 | .amixer_rsc_get_ctrl_blk = amixer_rsc_get_ctrl_blk, | ||
2071 | .amixer_rsc_put_ctrl_blk = amixer_rsc_put_ctrl_blk, | ||
2072 | .amixer_mgr_get_ctrl_blk = amixer_mgr_get_ctrl_blk, | ||
2073 | .amixer_mgr_put_ctrl_blk = amixer_mgr_put_ctrl_blk, | ||
2074 | .amixer_set_mode = amixer_set_mode, | ||
2075 | .amixer_set_iv = amixer_set_iv, | ||
2076 | .amixer_set_x = amixer_set_x, | ||
2077 | .amixer_set_y = amixer_set_y, | ||
2078 | .amixer_set_sadr = amixer_set_sadr, | ||
2079 | .amixer_set_se = amixer_set_se, | ||
2080 | .amixer_set_dirty = amixer_set_dirty, | ||
2081 | .amixer_set_dirty_all = amixer_set_dirty_all, | ||
2082 | .amixer_commit_write = amixer_commit_write, | ||
2083 | .amixer_get_y = amixer_get_y, | ||
2084 | .amixer_get_dirty = amixer_get_dirty, | ||
2085 | |||
2086 | .dai_get_ctrl_blk = dai_get_ctrl_blk, | ||
2087 | .dai_put_ctrl_blk = dai_put_ctrl_blk, | ||
2088 | .dai_srt_set_srco = dai_srt_set_srco, | ||
2089 | .dai_srt_set_srcm = dai_srt_set_srcm, | ||
2090 | .dai_srt_set_rsr = dai_srt_set_rsr, | ||
2091 | .dai_srt_set_drat = dai_srt_set_drat, | ||
2092 | .dai_srt_set_ec = dai_srt_set_ec, | ||
2093 | .dai_srt_set_et = dai_srt_set_et, | ||
2094 | .dai_commit_write = dai_commit_write, | ||
2095 | |||
2096 | .dao_get_ctrl_blk = dao_get_ctrl_blk, | ||
2097 | .dao_put_ctrl_blk = dao_put_ctrl_blk, | ||
2098 | .dao_set_spos = dao_set_spos, | ||
2099 | .dao_commit_write = dao_commit_write, | ||
2100 | .dao_get_spos = dao_get_spos, | ||
2101 | |||
2102 | .daio_mgr_get_ctrl_blk = daio_mgr_get_ctrl_blk, | ||
2103 | .daio_mgr_put_ctrl_blk = daio_mgr_put_ctrl_blk, | ||
2104 | .daio_mgr_enb_dai = daio_mgr_enb_dai, | ||
2105 | .daio_mgr_dsb_dai = daio_mgr_dsb_dai, | ||
2106 | .daio_mgr_enb_dao = daio_mgr_enb_dao, | ||
2107 | .daio_mgr_dsb_dao = daio_mgr_dsb_dao, | ||
2108 | .daio_mgr_dao_init = daio_mgr_dao_init, | ||
2109 | .daio_mgr_set_imaparc = daio_mgr_set_imaparc, | ||
2110 | .daio_mgr_set_imapnxt = daio_mgr_set_imapnxt, | ||
2111 | .daio_mgr_set_imapaddr = daio_mgr_set_imapaddr, | ||
2112 | .daio_mgr_commit_write = daio_mgr_commit_write, | ||
2113 | }; | ||
2114 | |||
2115 | int __devinit create_20k2_hw_obj(struct hw **rhw) | ||
2116 | { | ||
2117 | struct hw20k2 *hw20k2; | ||
2118 | |||
2119 | *rhw = NULL; | ||
2120 | hw20k2 = kzalloc(sizeof(*hw20k2), GFP_KERNEL); | ||
2121 | if (!hw20k2) | ||
2122 | return -ENOMEM; | ||
2123 | |||
2124 | hw20k2->hw = ct20k2_preset; | ||
2125 | *rhw = &hw20k2->hw; | ||
2126 | |||
2127 | return 0; | ||
2128 | } | ||
2129 | |||
2130 | int destroy_20k2_hw_obj(struct hw *hw) | ||
2131 | { | ||
2132 | if (hw->io_base) | ||
2133 | hw_card_shutdown(hw); | ||
2134 | |||
2135 | kfree(hw); | ||
2136 | return 0; | ||
2137 | } | ||
diff --git a/sound/pci/ctxfi/cthw20k2.h b/sound/pci/ctxfi/cthw20k2.h new file mode 100644 index 000000000000..d2b7daab6815 --- /dev/null +++ b/sound/pci/ctxfi/cthw20k2.h | |||
@@ -0,0 +1,26 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File cthw20k2.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of hardware access methord. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date May 13 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef CTHW20K2_H | ||
19 | #define CTHW20K2_H | ||
20 | |||
21 | #include "cthardware.h" | ||
22 | |||
23 | int create_20k2_hw_obj(struct hw **rhw); | ||
24 | int destroy_20k2_hw_obj(struct hw *hw); | ||
25 | |||
26 | #endif /* CTHW20K2_H */ | ||
diff --git a/sound/pci/ctxfi/ctimap.c b/sound/pci/ctxfi/ctimap.c new file mode 100644 index 000000000000..0b73368a4df6 --- /dev/null +++ b/sound/pci/ctxfi/ctimap.c | |||
@@ -0,0 +1,112 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctimap.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of generic input mapper operations | ||
12 | * for input mapper management. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 23 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "ctimap.h" | ||
20 | #include <linux/slab.h> | ||
21 | |||
22 | int input_mapper_add(struct list_head *mappers, struct imapper *entry, | ||
23 | int (*map_op)(void *, struct imapper *), void *data) | ||
24 | { | ||
25 | struct list_head *pos, *pre, *head; | ||
26 | struct imapper *pre_ent, *pos_ent; | ||
27 | |||
28 | head = mappers; | ||
29 | |||
30 | if (list_empty(head)) { | ||
31 | entry->next = entry->addr; | ||
32 | map_op(data, entry); | ||
33 | list_add(&entry->list, head); | ||
34 | return 0; | ||
35 | } | ||
36 | |||
37 | list_for_each(pos, head) { | ||
38 | pos_ent = list_entry(pos, struct imapper, list); | ||
39 | if (pos_ent->slot > entry->slot) { | ||
40 | /* found a position in list */ | ||
41 | break; | ||
42 | } | ||
43 | } | ||
44 | |||
45 | if (pos != head) { | ||
46 | pre = pos->prev; | ||
47 | if (pre == head) | ||
48 | pre = head->prev; | ||
49 | |||
50 | __list_add(&entry->list, pos->prev, pos); | ||
51 | } else { | ||
52 | pre = head->prev; | ||
53 | pos = head->next; | ||
54 | list_add_tail(&entry->list, head); | ||
55 | } | ||
56 | |||
57 | pre_ent = list_entry(pre, struct imapper, list); | ||
58 | pos_ent = list_entry(pos, struct imapper, list); | ||
59 | |||
60 | entry->next = pos_ent->addr; | ||
61 | map_op(data, entry); | ||
62 | pre_ent->next = entry->addr; | ||
63 | map_op(data, pre_ent); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | int input_mapper_delete(struct list_head *mappers, struct imapper *entry, | ||
69 | int (*map_op)(void *, struct imapper *), void *data) | ||
70 | { | ||
71 | struct list_head *next, *pre, *head; | ||
72 | struct imapper *pre_ent, *next_ent; | ||
73 | |||
74 | head = mappers; | ||
75 | |||
76 | if (list_empty(head)) | ||
77 | return 0; | ||
78 | |||
79 | pre = (entry->list.prev == head) ? head->prev : entry->list.prev; | ||
80 | next = (entry->list.next == head) ? head->next : entry->list.next; | ||
81 | |||
82 | if (pre == &entry->list) { | ||
83 | /* entry is the only one node in mappers list */ | ||
84 | entry->next = entry->addr = entry->user = entry->slot = 0; | ||
85 | map_op(data, entry); | ||
86 | list_del(&entry->list); | ||
87 | return 0; | ||
88 | } | ||
89 | |||
90 | pre_ent = list_entry(pre, struct imapper, list); | ||
91 | next_ent = list_entry(next, struct imapper, list); | ||
92 | |||
93 | pre_ent->next = next_ent->addr; | ||
94 | map_op(data, pre_ent); | ||
95 | list_del(&entry->list); | ||
96 | |||
97 | return 0; | ||
98 | } | ||
99 | |||
100 | void free_input_mapper_list(struct list_head *head) | ||
101 | { | ||
102 | struct imapper *entry; | ||
103 | struct list_head *pos; | ||
104 | |||
105 | while (!list_empty(head)) { | ||
106 | pos = head->next; | ||
107 | list_del(pos); | ||
108 | entry = list_entry(pos, struct imapper, list); | ||
109 | kfree(entry); | ||
110 | } | ||
111 | } | ||
112 | |||
diff --git a/sound/pci/ctxfi/ctimap.h b/sound/pci/ctxfi/ctimap.h new file mode 100644 index 000000000000..53ccf9be8b68 --- /dev/null +++ b/sound/pci/ctxfi/ctimap.h | |||
@@ -0,0 +1,40 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctimap.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of generic input mapper operations | ||
12 | * for input mapper management. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 23 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef CTIMAP_H | ||
20 | #define CTIMAP_H | ||
21 | |||
22 | #include <linux/list.h> | ||
23 | |||
24 | struct imapper { | ||
25 | unsigned short slot; /* the id of the slot containing input data */ | ||
26 | unsigned short user; /* the id of the user resource consuming data */ | ||
27 | unsigned short addr; /* the input mapper ram id */ | ||
28 | unsigned short next; /* the next input mapper ram id */ | ||
29 | struct list_head list; | ||
30 | }; | ||
31 | |||
32 | int input_mapper_add(struct list_head *mappers, struct imapper *entry, | ||
33 | int (*map_op)(void *, struct imapper *), void *data); | ||
34 | |||
35 | int input_mapper_delete(struct list_head *mappers, struct imapper *entry, | ||
36 | int (*map_op)(void *, struct imapper *), void *data); | ||
37 | |||
38 | void free_input_mapper_list(struct list_head *mappers); | ||
39 | |||
40 | #endif /* CTIMAP_H */ | ||
diff --git a/sound/pci/ctxfi/ctmixer.c b/sound/pci/ctxfi/ctmixer.c new file mode 100644 index 000000000000..666722d9de41 --- /dev/null +++ b/sound/pci/ctxfi/ctmixer.c | |||
@@ -0,0 +1,1123 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctmixer.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of alsa mixer device functions. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date May 28 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | |||
19 | #include "ctmixer.h" | ||
20 | #include "ctamixer.h" | ||
21 | #include <linux/slab.h> | ||
22 | #include <sound/core.h> | ||
23 | #include <sound/control.h> | ||
24 | #include <sound/asoundef.h> | ||
25 | #include <sound/pcm.h> | ||
26 | #include <sound/tlv.h> | ||
27 | |||
28 | enum CT_SUM_CTL { | ||
29 | SUM_IN_F, | ||
30 | SUM_IN_R, | ||
31 | SUM_IN_C, | ||
32 | SUM_IN_S, | ||
33 | SUM_IN_F_C, | ||
34 | |||
35 | NUM_CT_SUMS | ||
36 | }; | ||
37 | |||
38 | enum CT_AMIXER_CTL { | ||
39 | /* volume control mixers */ | ||
40 | AMIXER_MASTER_F, | ||
41 | AMIXER_MASTER_R, | ||
42 | AMIXER_MASTER_C, | ||
43 | AMIXER_MASTER_S, | ||
44 | AMIXER_PCM_F, | ||
45 | AMIXER_PCM_R, | ||
46 | AMIXER_PCM_C, | ||
47 | AMIXER_PCM_S, | ||
48 | AMIXER_SPDIFI, | ||
49 | AMIXER_LINEIN, | ||
50 | AMIXER_MIC, | ||
51 | AMIXER_SPDIFO, | ||
52 | AMIXER_WAVE_F, | ||
53 | AMIXER_WAVE_R, | ||
54 | AMIXER_WAVE_C, | ||
55 | AMIXER_WAVE_S, | ||
56 | AMIXER_MASTER_F_C, | ||
57 | AMIXER_PCM_F_C, | ||
58 | AMIXER_SPDIFI_C, | ||
59 | AMIXER_LINEIN_C, | ||
60 | AMIXER_MIC_C, | ||
61 | |||
62 | /* this should always be the last one */ | ||
63 | NUM_CT_AMIXERS | ||
64 | }; | ||
65 | |||
66 | enum CTALSA_MIXER_CTL { | ||
67 | /* volume control mixers */ | ||
68 | MIXER_MASTER_P, | ||
69 | MIXER_PCM_P, | ||
70 | MIXER_LINEIN_P, | ||
71 | MIXER_MIC_P, | ||
72 | MIXER_SPDIFI_P, | ||
73 | MIXER_SPDIFO_P, | ||
74 | MIXER_WAVEF_P, | ||
75 | MIXER_WAVER_P, | ||
76 | MIXER_WAVEC_P, | ||
77 | MIXER_WAVES_P, | ||
78 | MIXER_MASTER_C, | ||
79 | MIXER_PCM_C, | ||
80 | MIXER_LINEIN_C, | ||
81 | MIXER_MIC_C, | ||
82 | MIXER_SPDIFI_C, | ||
83 | |||
84 | /* switch control mixers */ | ||
85 | MIXER_PCM_C_S, | ||
86 | MIXER_LINEIN_C_S, | ||
87 | MIXER_MIC_C_S, | ||
88 | MIXER_SPDIFI_C_S, | ||
89 | MIXER_LINEIN_P_S, | ||
90 | MIXER_SPDIFO_P_S, | ||
91 | MIXER_SPDIFI_P_S, | ||
92 | MIXER_WAVEF_P_S, | ||
93 | MIXER_WAVER_P_S, | ||
94 | MIXER_WAVEC_P_S, | ||
95 | MIXER_WAVES_P_S, | ||
96 | MIXER_DIGITAL_IO_S, | ||
97 | MIXER_IEC958_MASK, | ||
98 | MIXER_IEC958_DEFAULT, | ||
99 | MIXER_IEC958_STREAM, | ||
100 | |||
101 | /* this should always be the last one */ | ||
102 | NUM_CTALSA_MIXERS | ||
103 | }; | ||
104 | |||
105 | #define VOL_MIXER_START MIXER_MASTER_P | ||
106 | #define VOL_MIXER_END MIXER_SPDIFI_C | ||
107 | #define VOL_MIXER_NUM (VOL_MIXER_END - VOL_MIXER_START + 1) | ||
108 | #define SWH_MIXER_START MIXER_PCM_C_S | ||
109 | #define SWH_MIXER_END MIXER_DIGITAL_IO_S | ||
110 | #define SWH_CAPTURE_START MIXER_PCM_C_S | ||
111 | #define SWH_CAPTURE_END MIXER_SPDIFI_C_S | ||
112 | |||
113 | #define CHN_NUM 2 | ||
114 | |||
115 | struct ct_kcontrol_init { | ||
116 | unsigned char ctl; | ||
117 | char *name; | ||
118 | }; | ||
119 | |||
120 | static struct ct_kcontrol_init | ||
121 | ct_kcontrol_init_table[NUM_CTALSA_MIXERS] = { | ||
122 | [MIXER_MASTER_P] = { | ||
123 | .ctl = 1, | ||
124 | .name = "Master Playback Volume", | ||
125 | }, | ||
126 | [MIXER_MASTER_C] = { | ||
127 | .ctl = 1, | ||
128 | .name = "Master Capture Volume", | ||
129 | }, | ||
130 | [MIXER_PCM_P] = { | ||
131 | .ctl = 1, | ||
132 | .name = "PCM Playback Volume", | ||
133 | }, | ||
134 | [MIXER_PCM_C] = { | ||
135 | .ctl = 1, | ||
136 | .name = "PCM Capture Volume", | ||
137 | }, | ||
138 | [MIXER_LINEIN_P] = { | ||
139 | .ctl = 1, | ||
140 | .name = "Line-in Playback Volume", | ||
141 | }, | ||
142 | [MIXER_LINEIN_C] = { | ||
143 | .ctl = 1, | ||
144 | .name = "Line-in Capture Volume", | ||
145 | }, | ||
146 | [MIXER_MIC_P] = { | ||
147 | .ctl = 1, | ||
148 | .name = "Mic Playback Volume", | ||
149 | }, | ||
150 | [MIXER_MIC_C] = { | ||
151 | .ctl = 1, | ||
152 | .name = "Mic Capture Volume", | ||
153 | }, | ||
154 | [MIXER_SPDIFI_P] = { | ||
155 | .ctl = 1, | ||
156 | .name = "S/PDIF-in Playback Volume", | ||
157 | }, | ||
158 | [MIXER_SPDIFI_C] = { | ||
159 | .ctl = 1, | ||
160 | .name = "S/PDIF-in Capture Volume", | ||
161 | }, | ||
162 | [MIXER_SPDIFO_P] = { | ||
163 | .ctl = 1, | ||
164 | .name = "S/PDIF-out Playback Volume", | ||
165 | }, | ||
166 | [MIXER_WAVEF_P] = { | ||
167 | .ctl = 1, | ||
168 | .name = "Front Playback Volume", | ||
169 | }, | ||
170 | [MIXER_WAVES_P] = { | ||
171 | .ctl = 1, | ||
172 | .name = "Side Playback Volume", | ||
173 | }, | ||
174 | [MIXER_WAVEC_P] = { | ||
175 | .ctl = 1, | ||
176 | .name = "Center/LFE Playback Volume", | ||
177 | }, | ||
178 | [MIXER_WAVER_P] = { | ||
179 | .ctl = 1, | ||
180 | .name = "Surround Playback Volume", | ||
181 | }, | ||
182 | |||
183 | [MIXER_PCM_C_S] = { | ||
184 | .ctl = 1, | ||
185 | .name = "PCM Capture Switch", | ||
186 | }, | ||
187 | [MIXER_LINEIN_C_S] = { | ||
188 | .ctl = 1, | ||
189 | .name = "Line-in Capture Switch", | ||
190 | }, | ||
191 | [MIXER_MIC_C_S] = { | ||
192 | .ctl = 1, | ||
193 | .name = "Mic Capture Switch", | ||
194 | }, | ||
195 | [MIXER_SPDIFI_C_S] = { | ||
196 | .ctl = 1, | ||
197 | .name = "S/PDIF-in Capture Switch", | ||
198 | }, | ||
199 | [MIXER_LINEIN_P_S] = { | ||
200 | .ctl = 1, | ||
201 | .name = "Line-in Playback Switch", | ||
202 | }, | ||
203 | [MIXER_SPDIFO_P_S] = { | ||
204 | .ctl = 1, | ||
205 | .name = "S/PDIF-out Playback Switch", | ||
206 | }, | ||
207 | [MIXER_SPDIFI_P_S] = { | ||
208 | .ctl = 1, | ||
209 | .name = "S/PDIF-in Playback Switch", | ||
210 | }, | ||
211 | [MIXER_WAVEF_P_S] = { | ||
212 | .ctl = 1, | ||
213 | .name = "Front Playback Switch", | ||
214 | }, | ||
215 | [MIXER_WAVES_P_S] = { | ||
216 | .ctl = 1, | ||
217 | .name = "Side Playback Switch", | ||
218 | }, | ||
219 | [MIXER_WAVEC_P_S] = { | ||
220 | .ctl = 1, | ||
221 | .name = "Center/LFE Playback Switch", | ||
222 | }, | ||
223 | [MIXER_WAVER_P_S] = { | ||
224 | .ctl = 1, | ||
225 | .name = "Surround Playback Switch", | ||
226 | }, | ||
227 | [MIXER_DIGITAL_IO_S] = { | ||
228 | .ctl = 0, | ||
229 | .name = "Digit-IO Playback Switch", | ||
230 | }, | ||
231 | }; | ||
232 | |||
233 | static void | ||
234 | ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); | ||
235 | |||
236 | static void | ||
237 | ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type); | ||
238 | |||
239 | static struct snd_kcontrol *kctls[2] = {NULL}; | ||
240 | |||
241 | static enum CT_AMIXER_CTL get_amixer_index(enum CTALSA_MIXER_CTL alsa_index) | ||
242 | { | ||
243 | switch (alsa_index) { | ||
244 | case MIXER_MASTER_P: return AMIXER_MASTER_F; | ||
245 | case MIXER_MASTER_C: return AMIXER_MASTER_F_C; | ||
246 | case MIXER_PCM_P: return AMIXER_PCM_F; | ||
247 | case MIXER_PCM_C: | ||
248 | case MIXER_PCM_C_S: return AMIXER_PCM_F_C; | ||
249 | case MIXER_LINEIN_P: return AMIXER_LINEIN; | ||
250 | case MIXER_LINEIN_C: | ||
251 | case MIXER_LINEIN_C_S: return AMIXER_LINEIN_C; | ||
252 | case MIXER_MIC_P: return AMIXER_MIC; | ||
253 | case MIXER_MIC_C: | ||
254 | case MIXER_MIC_C_S: return AMIXER_MIC_C; | ||
255 | case MIXER_SPDIFI_P: return AMIXER_SPDIFI; | ||
256 | case MIXER_SPDIFI_C: | ||
257 | case MIXER_SPDIFI_C_S: return AMIXER_SPDIFI_C; | ||
258 | case MIXER_SPDIFO_P: return AMIXER_SPDIFO; | ||
259 | case MIXER_WAVEF_P: return AMIXER_WAVE_F; | ||
260 | case MIXER_WAVES_P: return AMIXER_WAVE_S; | ||
261 | case MIXER_WAVEC_P: return AMIXER_WAVE_C; | ||
262 | case MIXER_WAVER_P: return AMIXER_WAVE_R; | ||
263 | default: return NUM_CT_AMIXERS; | ||
264 | } | ||
265 | } | ||
266 | |||
267 | static enum CT_AMIXER_CTL get_recording_amixer(enum CT_AMIXER_CTL index) | ||
268 | { | ||
269 | switch (index) { | ||
270 | case AMIXER_MASTER_F: return AMIXER_MASTER_F_C; | ||
271 | case AMIXER_PCM_F: return AMIXER_PCM_F_C; | ||
272 | case AMIXER_SPDIFI: return AMIXER_SPDIFI_C; | ||
273 | case AMIXER_LINEIN: return AMIXER_LINEIN_C; | ||
274 | case AMIXER_MIC: return AMIXER_MIC_C; | ||
275 | default: return NUM_CT_AMIXERS; | ||
276 | } | ||
277 | } | ||
278 | |||
279 | static unsigned char | ||
280 | get_switch_state(struct ct_mixer *mixer, enum CTALSA_MIXER_CTL type) | ||
281 | { | ||
282 | return (mixer->switch_state & (0x1 << (type - SWH_MIXER_START))) | ||
283 | ? 1 : 0; | ||
284 | } | ||
285 | |||
286 | static void | ||
287 | set_switch_state(struct ct_mixer *mixer, | ||
288 | enum CTALSA_MIXER_CTL type, unsigned char state) | ||
289 | { | ||
290 | if (state) | ||
291 | mixer->switch_state |= (0x1 << (type - SWH_MIXER_START)); | ||
292 | else | ||
293 | mixer->switch_state &= ~(0x1 << (type - SWH_MIXER_START)); | ||
294 | } | ||
295 | |||
296 | #if 0 /* not used */ | ||
297 | /* Map integer value ranging from 0 to 65535 to 14-bit float value ranging | ||
298 | * from 2^-6 to (1+1023/1024) */ | ||
299 | static unsigned int uint16_to_float14(unsigned int x) | ||
300 | { | ||
301 | unsigned int i; | ||
302 | |||
303 | if (x < 17) | ||
304 | return 0; | ||
305 | |||
306 | x *= 2031; | ||
307 | x /= 65535; | ||
308 | x += 16; | ||
309 | |||
310 | /* i <= 6 */ | ||
311 | for (i = 0; !(x & 0x400); i++) | ||
312 | x <<= 1; | ||
313 | |||
314 | x = (((7 - i) & 0x7) << 10) | (x & 0x3ff); | ||
315 | |||
316 | return x; | ||
317 | } | ||
318 | |||
319 | static unsigned int float14_to_uint16(unsigned int x) | ||
320 | { | ||
321 | unsigned int e; | ||
322 | |||
323 | if (!x) | ||
324 | return x; | ||
325 | |||
326 | e = (x >> 10) & 0x7; | ||
327 | x &= 0x3ff; | ||
328 | x += 1024; | ||
329 | x >>= (7 - e); | ||
330 | x -= 16; | ||
331 | x *= 65535; | ||
332 | x /= 2031; | ||
333 | |||
334 | return x; | ||
335 | } | ||
336 | #endif /* not used */ | ||
337 | |||
338 | #define VOL_SCALE 0x1c | ||
339 | #define VOL_MAX 0x100 | ||
340 | |||
341 | static const DECLARE_TLV_DB_SCALE(ct_vol_db_scale, -6400, 25, 1); | ||
342 | |||
343 | static int ct_alsa_mix_volume_info(struct snd_kcontrol *kcontrol, | ||
344 | struct snd_ctl_elem_info *uinfo) | ||
345 | { | ||
346 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
347 | uinfo->count = 2; | ||
348 | uinfo->value.integer.min = 0; | ||
349 | uinfo->value.integer.max = VOL_MAX; | ||
350 | |||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static int ct_alsa_mix_volume_get(struct snd_kcontrol *kcontrol, | ||
355 | struct snd_ctl_elem_value *ucontrol) | ||
356 | { | ||
357 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
358 | enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value); | ||
359 | struct amixer *amixer; | ||
360 | int i, val; | ||
361 | |||
362 | for (i = 0; i < 2; i++) { | ||
363 | amixer = ((struct ct_mixer *)atc->mixer)-> | ||
364 | amixers[type*CHN_NUM+i]; | ||
365 | val = amixer->ops->get_scale(amixer) / VOL_SCALE; | ||
366 | if (val < 0) | ||
367 | val = 0; | ||
368 | else if (val > VOL_MAX) | ||
369 | val = VOL_MAX; | ||
370 | ucontrol->value.integer.value[i] = val; | ||
371 | } | ||
372 | |||
373 | return 0; | ||
374 | } | ||
375 | |||
376 | static int ct_alsa_mix_volume_put(struct snd_kcontrol *kcontrol, | ||
377 | struct snd_ctl_elem_value *ucontrol) | ||
378 | { | ||
379 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
380 | struct ct_mixer *mixer = atc->mixer; | ||
381 | enum CT_AMIXER_CTL type = get_amixer_index(kcontrol->private_value); | ||
382 | struct amixer *amixer; | ||
383 | int i, j, val, oval, change = 0; | ||
384 | |||
385 | for (i = 0; i < 2; i++) { | ||
386 | val = ucontrol->value.integer.value[i]; | ||
387 | if (val < 0) | ||
388 | val = 0; | ||
389 | else if (val > VOL_MAX) | ||
390 | val = VOL_MAX; | ||
391 | val *= VOL_SCALE; | ||
392 | amixer = mixer->amixers[type*CHN_NUM+i]; | ||
393 | oval = amixer->ops->get_scale(amixer); | ||
394 | if (val != oval) { | ||
395 | amixer->ops->set_scale(amixer, val); | ||
396 | amixer->ops->commit_write(amixer); | ||
397 | change = 1; | ||
398 | /* Synchronize Master/PCM playback AMIXERs. */ | ||
399 | if (AMIXER_MASTER_F == type || AMIXER_PCM_F == type) { | ||
400 | for (j = 1; j < 4; j++) { | ||
401 | amixer = mixer-> | ||
402 | amixers[(type+j)*CHN_NUM+i]; | ||
403 | amixer->ops->set_scale(amixer, val); | ||
404 | amixer->ops->commit_write(amixer); | ||
405 | } | ||
406 | } | ||
407 | } | ||
408 | } | ||
409 | |||
410 | return change; | ||
411 | } | ||
412 | |||
413 | static struct snd_kcontrol_new vol_ctl = { | ||
414 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
415 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
416 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
417 | .info = ct_alsa_mix_volume_info, | ||
418 | .get = ct_alsa_mix_volume_get, | ||
419 | .put = ct_alsa_mix_volume_put, | ||
420 | .tlv = { .p = ct_vol_db_scale }, | ||
421 | }; | ||
422 | |||
423 | static void | ||
424 | do_line_mic_switch(struct ct_atc *atc, enum CTALSA_MIXER_CTL type) | ||
425 | { | ||
426 | |||
427 | if (MIXER_LINEIN_C_S == type) { | ||
428 | atc->select_line_in(atc); | ||
429 | set_switch_state(atc->mixer, MIXER_MIC_C_S, 0); | ||
430 | snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
431 | &kctls[1]->id); | ||
432 | } else if (MIXER_MIC_C_S == type) { | ||
433 | atc->select_mic_in(atc); | ||
434 | set_switch_state(atc->mixer, MIXER_LINEIN_C_S, 0); | ||
435 | snd_ctl_notify(atc->card, SNDRV_CTL_EVENT_MASK_VALUE, | ||
436 | &kctls[0]->id); | ||
437 | } | ||
438 | } | ||
439 | |||
440 | static void | ||
441 | do_digit_io_switch(struct ct_atc *atc, int state) | ||
442 | { | ||
443 | struct ct_mixer *mixer = atc->mixer; | ||
444 | |||
445 | if (state) { | ||
446 | atc->select_digit_io(atc); | ||
447 | atc->spdif_out_unmute(atc, | ||
448 | get_switch_state(mixer, MIXER_SPDIFO_P_S)); | ||
449 | atc->spdif_in_unmute(atc, 1); | ||
450 | atc->line_in_unmute(atc, 0); | ||
451 | return; | ||
452 | } | ||
453 | |||
454 | if (get_switch_state(mixer, MIXER_LINEIN_C_S)) | ||
455 | atc->select_line_in(atc); | ||
456 | else if (get_switch_state(mixer, MIXER_MIC_C_S)) | ||
457 | atc->select_mic_in(atc); | ||
458 | |||
459 | atc->spdif_out_unmute(atc, 0); | ||
460 | atc->spdif_in_unmute(atc, 0); | ||
461 | atc->line_in_unmute(atc, 1); | ||
462 | return; | ||
463 | } | ||
464 | |||
465 | static int ct_alsa_mix_switch_info(struct snd_kcontrol *kcontrol, | ||
466 | struct snd_ctl_elem_info *uinfo) | ||
467 | { | ||
468 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
469 | uinfo->count = 1; | ||
470 | uinfo->value.integer.min = 0; | ||
471 | uinfo->value.integer.max = 1; | ||
472 | uinfo->value.integer.step = 1; | ||
473 | |||
474 | return 0; | ||
475 | } | ||
476 | |||
477 | static int ct_alsa_mix_switch_get(struct snd_kcontrol *kcontrol, | ||
478 | struct snd_ctl_elem_value *ucontrol) | ||
479 | { | ||
480 | struct ct_mixer *mixer = | ||
481 | ((struct ct_atc *)snd_kcontrol_chip(kcontrol))->mixer; | ||
482 | enum CTALSA_MIXER_CTL type = kcontrol->private_value; | ||
483 | |||
484 | ucontrol->value.integer.value[0] = get_switch_state(mixer, type); | ||
485 | return 0; | ||
486 | } | ||
487 | |||
488 | static int ct_alsa_mix_switch_put(struct snd_kcontrol *kcontrol, | ||
489 | struct snd_ctl_elem_value *ucontrol) | ||
490 | { | ||
491 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
492 | struct ct_mixer *mixer = atc->mixer; | ||
493 | enum CTALSA_MIXER_CTL type = kcontrol->private_value; | ||
494 | int state; | ||
495 | |||
496 | state = ucontrol->value.integer.value[0]; | ||
497 | if (get_switch_state(mixer, type) == state) | ||
498 | return 0; | ||
499 | |||
500 | set_switch_state(mixer, type, state); | ||
501 | /* Do changes in mixer. */ | ||
502 | if ((SWH_CAPTURE_START <= type) && (SWH_CAPTURE_END >= type)) { | ||
503 | if (state) { | ||
504 | ct_mixer_recording_select(mixer, | ||
505 | get_amixer_index(type)); | ||
506 | } else { | ||
507 | ct_mixer_recording_unselect(mixer, | ||
508 | get_amixer_index(type)); | ||
509 | } | ||
510 | } | ||
511 | /* Do changes out of mixer. */ | ||
512 | if (state && (MIXER_LINEIN_C_S == type || MIXER_MIC_C_S == type)) | ||
513 | do_line_mic_switch(atc, type); | ||
514 | else if (MIXER_WAVEF_P_S == type) | ||
515 | atc->line_front_unmute(atc, state); | ||
516 | else if (MIXER_WAVES_P_S == type) | ||
517 | atc->line_surround_unmute(atc, state); | ||
518 | else if (MIXER_WAVEC_P_S == type) | ||
519 | atc->line_clfe_unmute(atc, state); | ||
520 | else if (MIXER_WAVER_P_S == type) | ||
521 | atc->line_rear_unmute(atc, state); | ||
522 | else if (MIXER_LINEIN_P_S == type) | ||
523 | atc->line_in_unmute(atc, state); | ||
524 | else if (MIXER_SPDIFO_P_S == type) | ||
525 | atc->spdif_out_unmute(atc, state); | ||
526 | else if (MIXER_SPDIFI_P_S == type) | ||
527 | atc->spdif_in_unmute(atc, state); | ||
528 | else if (MIXER_DIGITAL_IO_S == type) | ||
529 | do_digit_io_switch(atc, state); | ||
530 | |||
531 | return 1; | ||
532 | } | ||
533 | |||
534 | static struct snd_kcontrol_new swh_ctl = { | ||
535 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
536 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
537 | .info = ct_alsa_mix_switch_info, | ||
538 | .get = ct_alsa_mix_switch_get, | ||
539 | .put = ct_alsa_mix_switch_put | ||
540 | }; | ||
541 | |||
542 | static int ct_spdif_info(struct snd_kcontrol *kcontrol, | ||
543 | struct snd_ctl_elem_info *uinfo) | ||
544 | { | ||
545 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | ||
546 | uinfo->count = 1; | ||
547 | return 0; | ||
548 | } | ||
549 | |||
550 | static int ct_spdif_get_mask(struct snd_kcontrol *kcontrol, | ||
551 | struct snd_ctl_elem_value *ucontrol) | ||
552 | { | ||
553 | ucontrol->value.iec958.status[0] = 0xff; | ||
554 | ucontrol->value.iec958.status[1] = 0xff; | ||
555 | ucontrol->value.iec958.status[2] = 0xff; | ||
556 | ucontrol->value.iec958.status[3] = 0xff; | ||
557 | return 0; | ||
558 | } | ||
559 | |||
560 | static int ct_spdif_default_get(struct snd_kcontrol *kcontrol, | ||
561 | struct snd_ctl_elem_value *ucontrol) | ||
562 | { | ||
563 | unsigned int status = SNDRV_PCM_DEFAULT_CON_SPDIF; | ||
564 | |||
565 | ucontrol->value.iec958.status[0] = (status >> 0) & 0xff; | ||
566 | ucontrol->value.iec958.status[1] = (status >> 8) & 0xff; | ||
567 | ucontrol->value.iec958.status[2] = (status >> 16) & 0xff; | ||
568 | ucontrol->value.iec958.status[3] = (status >> 24) & 0xff; | ||
569 | |||
570 | return 0; | ||
571 | } | ||
572 | |||
573 | static int ct_spdif_get(struct snd_kcontrol *kcontrol, | ||
574 | struct snd_ctl_elem_value *ucontrol) | ||
575 | { | ||
576 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
577 | unsigned int status; | ||
578 | |||
579 | atc->spdif_out_get_status(atc, &status); | ||
580 | ucontrol->value.iec958.status[0] = (status >> 0) & 0xff; | ||
581 | ucontrol->value.iec958.status[1] = (status >> 8) & 0xff; | ||
582 | ucontrol->value.iec958.status[2] = (status >> 16) & 0xff; | ||
583 | ucontrol->value.iec958.status[3] = (status >> 24) & 0xff; | ||
584 | |||
585 | return 0; | ||
586 | } | ||
587 | |||
588 | static int ct_spdif_put(struct snd_kcontrol *kcontrol, | ||
589 | struct snd_ctl_elem_value *ucontrol) | ||
590 | { | ||
591 | struct ct_atc *atc = snd_kcontrol_chip(kcontrol); | ||
592 | int change; | ||
593 | unsigned int status, old_status; | ||
594 | |||
595 | status = (ucontrol->value.iec958.status[0] << 0) | | ||
596 | (ucontrol->value.iec958.status[1] << 8) | | ||
597 | (ucontrol->value.iec958.status[2] << 16) | | ||
598 | (ucontrol->value.iec958.status[3] << 24); | ||
599 | |||
600 | atc->spdif_out_get_status(atc, &old_status); | ||
601 | change = (old_status != status); | ||
602 | if (change) | ||
603 | atc->spdif_out_set_status(atc, status); | ||
604 | |||
605 | return change; | ||
606 | } | ||
607 | |||
608 | static struct snd_kcontrol_new iec958_mask_ctl = { | ||
609 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
610 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
611 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), | ||
612 | .count = 1, | ||
613 | .info = ct_spdif_info, | ||
614 | .get = ct_spdif_get_mask, | ||
615 | .private_value = MIXER_IEC958_MASK | ||
616 | }; | ||
617 | |||
618 | static struct snd_kcontrol_new iec958_default_ctl = { | ||
619 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
620 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), | ||
621 | .count = 1, | ||
622 | .info = ct_spdif_info, | ||
623 | .get = ct_spdif_default_get, | ||
624 | .put = ct_spdif_put, | ||
625 | .private_value = MIXER_IEC958_DEFAULT | ||
626 | }; | ||
627 | |||
628 | static struct snd_kcontrol_new iec958_ctl = { | ||
629 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
630 | .iface = SNDRV_CTL_ELEM_IFACE_PCM, | ||
631 | .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, PCM_STREAM), | ||
632 | .count = 1, | ||
633 | .info = ct_spdif_info, | ||
634 | .get = ct_spdif_get, | ||
635 | .put = ct_spdif_put, | ||
636 | .private_value = MIXER_IEC958_STREAM | ||
637 | }; | ||
638 | |||
639 | #define NUM_IEC958_CTL 3 | ||
640 | |||
641 | static int | ||
642 | ct_mixer_kcontrol_new(struct ct_mixer *mixer, struct snd_kcontrol_new *new) | ||
643 | { | ||
644 | struct snd_kcontrol *kctl; | ||
645 | int err; | ||
646 | |||
647 | kctl = snd_ctl_new1(new, mixer->atc); | ||
648 | if (NULL == kctl) | ||
649 | return -ENOMEM; | ||
650 | |||
651 | if (SNDRV_CTL_ELEM_IFACE_PCM == kctl->id.iface) | ||
652 | kctl->id.device = IEC958; | ||
653 | |||
654 | err = snd_ctl_add(mixer->atc->card, kctl); | ||
655 | if (err) | ||
656 | return err; | ||
657 | |||
658 | switch (new->private_value) { | ||
659 | case MIXER_LINEIN_C_S: | ||
660 | kctls[0] = kctl; break; | ||
661 | case MIXER_MIC_C_S: | ||
662 | kctls[1] = kctl; break; | ||
663 | default: | ||
664 | break; | ||
665 | } | ||
666 | |||
667 | return 0; | ||
668 | } | ||
669 | |||
670 | static int ct_mixer_kcontrols_create(struct ct_mixer *mixer) | ||
671 | { | ||
672 | enum CTALSA_MIXER_CTL type; | ||
673 | struct ct_atc *atc = mixer->atc; | ||
674 | int err; | ||
675 | |||
676 | /* Create snd kcontrol instances on demand */ | ||
677 | for (type = VOL_MIXER_START; type <= VOL_MIXER_END; type++) { | ||
678 | if (ct_kcontrol_init_table[type].ctl) { | ||
679 | vol_ctl.name = ct_kcontrol_init_table[type].name; | ||
680 | vol_ctl.private_value = (unsigned long)type; | ||
681 | err = ct_mixer_kcontrol_new(mixer, &vol_ctl); | ||
682 | if (err) | ||
683 | return err; | ||
684 | } | ||
685 | } | ||
686 | |||
687 | ct_kcontrol_init_table[MIXER_DIGITAL_IO_S].ctl = | ||
688 | atc->have_digit_io_switch(atc); | ||
689 | for (type = SWH_MIXER_START; type <= SWH_MIXER_END; type++) { | ||
690 | if (ct_kcontrol_init_table[type].ctl) { | ||
691 | swh_ctl.name = ct_kcontrol_init_table[type].name; | ||
692 | swh_ctl.private_value = (unsigned long)type; | ||
693 | err = ct_mixer_kcontrol_new(mixer, &swh_ctl); | ||
694 | if (err) | ||
695 | return err; | ||
696 | } | ||
697 | } | ||
698 | |||
699 | err = ct_mixer_kcontrol_new(mixer, &iec958_mask_ctl); | ||
700 | if (err) | ||
701 | return err; | ||
702 | |||
703 | err = ct_mixer_kcontrol_new(mixer, &iec958_default_ctl); | ||
704 | if (err) | ||
705 | return err; | ||
706 | |||
707 | err = ct_mixer_kcontrol_new(mixer, &iec958_ctl); | ||
708 | if (err) | ||
709 | return err; | ||
710 | |||
711 | atc->line_front_unmute(atc, 1); | ||
712 | set_switch_state(mixer, MIXER_WAVEF_P_S, 1); | ||
713 | atc->line_surround_unmute(atc, 0); | ||
714 | set_switch_state(mixer, MIXER_WAVES_P_S, 0); | ||
715 | atc->line_clfe_unmute(atc, 0); | ||
716 | set_switch_state(mixer, MIXER_WAVEC_P_S, 0); | ||
717 | atc->line_rear_unmute(atc, 0); | ||
718 | set_switch_state(mixer, MIXER_WAVER_P_S, 0); | ||
719 | atc->spdif_out_unmute(atc, 0); | ||
720 | set_switch_state(mixer, MIXER_SPDIFO_P_S, 0); | ||
721 | atc->line_in_unmute(atc, 0); | ||
722 | set_switch_state(mixer, MIXER_LINEIN_P_S, 0); | ||
723 | atc->spdif_in_unmute(atc, 0); | ||
724 | set_switch_state(mixer, MIXER_SPDIFI_P_S, 0); | ||
725 | |||
726 | set_switch_state(mixer, MIXER_PCM_C_S, 1); | ||
727 | set_switch_state(mixer, MIXER_LINEIN_C_S, 1); | ||
728 | set_switch_state(mixer, MIXER_SPDIFI_C_S, 1); | ||
729 | |||
730 | return 0; | ||
731 | } | ||
732 | |||
733 | static void | ||
734 | ct_mixer_recording_select(struct ct_mixer *mixer, enum CT_AMIXER_CTL type) | ||
735 | { | ||
736 | struct amixer *amix_d; | ||
737 | struct sum *sum_c; | ||
738 | int i; | ||
739 | |||
740 | for (i = 0; i < 2; i++) { | ||
741 | amix_d = mixer->amixers[type*CHN_NUM+i]; | ||
742 | sum_c = mixer->sums[SUM_IN_F_C*CHN_NUM+i]; | ||
743 | amix_d->ops->set_sum(amix_d, sum_c); | ||
744 | amix_d->ops->commit_write(amix_d); | ||
745 | } | ||
746 | } | ||
747 | |||
748 | static void | ||
749 | ct_mixer_recording_unselect(struct ct_mixer *mixer, enum CT_AMIXER_CTL type) | ||
750 | { | ||
751 | struct amixer *amix_d; | ||
752 | int i; | ||
753 | |||
754 | for (i = 0; i < 2; i++) { | ||
755 | amix_d = mixer->amixers[type*CHN_NUM+i]; | ||
756 | amix_d->ops->set_sum(amix_d, NULL); | ||
757 | amix_d->ops->commit_write(amix_d); | ||
758 | } | ||
759 | } | ||
760 | |||
761 | static int ct_mixer_get_resources(struct ct_mixer *mixer) | ||
762 | { | ||
763 | struct sum_mgr *sum_mgr; | ||
764 | struct sum *sum; | ||
765 | struct sum_desc sum_desc = {0}; | ||
766 | struct amixer_mgr *amixer_mgr; | ||
767 | struct amixer *amixer; | ||
768 | struct amixer_desc am_desc = {0}; | ||
769 | int err; | ||
770 | int i; | ||
771 | |||
772 | /* Allocate sum resources for mixer obj */ | ||
773 | sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM]; | ||
774 | sum_desc.msr = mixer->atc->msr; | ||
775 | for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { | ||
776 | err = sum_mgr->get_sum(sum_mgr, &sum_desc, &sum); | ||
777 | if (err) { | ||
778 | printk(KERN_ERR "ctxfi:Failed to get sum resources for " | ||
779 | "front output!\n"); | ||
780 | break; | ||
781 | } | ||
782 | mixer->sums[i] = sum; | ||
783 | } | ||
784 | if (err) | ||
785 | goto error1; | ||
786 | |||
787 | /* Allocate amixer resources for mixer obj */ | ||
788 | amixer_mgr = (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER]; | ||
789 | am_desc.msr = mixer->atc->msr; | ||
790 | for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { | ||
791 | err = amixer_mgr->get_amixer(amixer_mgr, &am_desc, &amixer); | ||
792 | if (err) { | ||
793 | printk(KERN_ERR "ctxfi:Failed to get amixer resources " | ||
794 | "for mixer obj!\n"); | ||
795 | break; | ||
796 | } | ||
797 | mixer->amixers[i] = amixer; | ||
798 | } | ||
799 | if (err) | ||
800 | goto error2; | ||
801 | |||
802 | return 0; | ||
803 | |||
804 | error2: | ||
805 | for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { | ||
806 | if (NULL != mixer->amixers[i]) { | ||
807 | amixer = mixer->amixers[i]; | ||
808 | amixer_mgr->put_amixer(amixer_mgr, amixer); | ||
809 | mixer->amixers[i] = NULL; | ||
810 | } | ||
811 | } | ||
812 | error1: | ||
813 | for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { | ||
814 | if (NULL != mixer->sums[i]) { | ||
815 | sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]); | ||
816 | mixer->sums[i] = NULL; | ||
817 | } | ||
818 | } | ||
819 | |||
820 | return err; | ||
821 | } | ||
822 | |||
823 | static int ct_mixer_get_mem(struct ct_mixer **rmixer) | ||
824 | { | ||
825 | struct ct_mixer *mixer; | ||
826 | int err; | ||
827 | |||
828 | *rmixer = NULL; | ||
829 | /* Allocate mem for mixer obj */ | ||
830 | mixer = kzalloc(sizeof(*mixer), GFP_KERNEL); | ||
831 | if (NULL == mixer) | ||
832 | return -ENOMEM; | ||
833 | |||
834 | mixer->amixers = kzalloc(sizeof(void *)*(NUM_CT_AMIXERS*CHN_NUM), | ||
835 | GFP_KERNEL); | ||
836 | if (NULL == mixer->amixers) { | ||
837 | err = -ENOMEM; | ||
838 | goto error1; | ||
839 | } | ||
840 | mixer->sums = kzalloc(sizeof(void *)*(NUM_CT_SUMS*CHN_NUM), GFP_KERNEL); | ||
841 | if (NULL == mixer->sums) { | ||
842 | err = -ENOMEM; | ||
843 | goto error2; | ||
844 | } | ||
845 | |||
846 | *rmixer = mixer; | ||
847 | return 0; | ||
848 | |||
849 | error2: | ||
850 | kfree(mixer->amixers); | ||
851 | error1: | ||
852 | kfree(mixer); | ||
853 | return err; | ||
854 | } | ||
855 | |||
856 | static int ct_mixer_topology_build(struct ct_mixer *mixer) | ||
857 | { | ||
858 | struct sum *sum; | ||
859 | struct amixer *amix_d, *amix_s; | ||
860 | enum CT_AMIXER_CTL i, j; | ||
861 | |||
862 | /* Build topology from destination to source */ | ||
863 | |||
864 | /* Set up Master mixer */ | ||
865 | for (i = AMIXER_MASTER_F, j = SUM_IN_F; | ||
866 | i <= AMIXER_MASTER_S; i++, j++) { | ||
867 | amix_d = mixer->amixers[i*CHN_NUM]; | ||
868 | sum = mixer->sums[j*CHN_NUM]; | ||
869 | amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); | ||
870 | amix_d = mixer->amixers[i*CHN_NUM+1]; | ||
871 | sum = mixer->sums[j*CHN_NUM+1]; | ||
872 | amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); | ||
873 | } | ||
874 | |||
875 | /* Set up Wave-out mixer */ | ||
876 | for (i = AMIXER_WAVE_F, j = AMIXER_MASTER_F; | ||
877 | i <= AMIXER_WAVE_S; i++, j++) { | ||
878 | amix_d = mixer->amixers[i*CHN_NUM]; | ||
879 | amix_s = mixer->amixers[j*CHN_NUM]; | ||
880 | amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); | ||
881 | amix_d = mixer->amixers[i*CHN_NUM+1]; | ||
882 | amix_s = mixer->amixers[j*CHN_NUM+1]; | ||
883 | amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); | ||
884 | } | ||
885 | |||
886 | /* Set up S/PDIF-out mixer */ | ||
887 | amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM]; | ||
888 | amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM]; | ||
889 | amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); | ||
890 | amix_d = mixer->amixers[AMIXER_SPDIFO*CHN_NUM+1]; | ||
891 | amix_s = mixer->amixers[AMIXER_MASTER_F*CHN_NUM+1]; | ||
892 | amix_d->ops->setup(amix_d, &amix_s->rsc, INIT_VOL, NULL); | ||
893 | |||
894 | /* Set up PCM-in mixer */ | ||
895 | for (i = AMIXER_PCM_F, j = SUM_IN_F; i <= AMIXER_PCM_S; i++, j++) { | ||
896 | amix_d = mixer->amixers[i*CHN_NUM]; | ||
897 | sum = mixer->sums[j*CHN_NUM]; | ||
898 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
899 | amix_d = mixer->amixers[i*CHN_NUM+1]; | ||
900 | sum = mixer->sums[j*CHN_NUM+1]; | ||
901 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
902 | } | ||
903 | |||
904 | /* Set up Line-in mixer */ | ||
905 | amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM]; | ||
906 | sum = mixer->sums[SUM_IN_F*CHN_NUM]; | ||
907 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
908 | amix_d = mixer->amixers[AMIXER_LINEIN*CHN_NUM+1]; | ||
909 | sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; | ||
910 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
911 | |||
912 | /* Set up Mic-in mixer */ | ||
913 | amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM]; | ||
914 | sum = mixer->sums[SUM_IN_F*CHN_NUM]; | ||
915 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
916 | amix_d = mixer->amixers[AMIXER_MIC*CHN_NUM+1]; | ||
917 | sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; | ||
918 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
919 | |||
920 | /* Set up S/PDIF-in mixer */ | ||
921 | amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM]; | ||
922 | sum = mixer->sums[SUM_IN_F*CHN_NUM]; | ||
923 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
924 | amix_d = mixer->amixers[AMIXER_SPDIFI*CHN_NUM+1]; | ||
925 | sum = mixer->sums[SUM_IN_F*CHN_NUM+1]; | ||
926 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
927 | |||
928 | /* Set up Master recording mixer */ | ||
929 | amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM]; | ||
930 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; | ||
931 | amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); | ||
932 | amix_d = mixer->amixers[AMIXER_MASTER_F_C*CHN_NUM+1]; | ||
933 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; | ||
934 | amix_d->ops->setup(amix_d, &sum->rsc, INIT_VOL, NULL); | ||
935 | |||
936 | /* Set up PCM-in recording mixer */ | ||
937 | amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM]; | ||
938 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; | ||
939 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
940 | amix_d = mixer->amixers[AMIXER_PCM_F_C*CHN_NUM+1]; | ||
941 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; | ||
942 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
943 | |||
944 | /* Set up Line-in recording mixer */ | ||
945 | amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM]; | ||
946 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; | ||
947 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
948 | amix_d = mixer->amixers[AMIXER_LINEIN_C*CHN_NUM+1]; | ||
949 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; | ||
950 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
951 | |||
952 | /* Set up Mic-in recording mixer */ | ||
953 | amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM]; | ||
954 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; | ||
955 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
956 | amix_d = mixer->amixers[AMIXER_MIC_C*CHN_NUM+1]; | ||
957 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; | ||
958 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
959 | |||
960 | /* Set up S/PDIF-in recording mixer */ | ||
961 | amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM]; | ||
962 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM]; | ||
963 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
964 | amix_d = mixer->amixers[AMIXER_SPDIFI_C*CHN_NUM+1]; | ||
965 | sum = mixer->sums[SUM_IN_F_C*CHN_NUM+1]; | ||
966 | amix_d->ops->setup(amix_d, NULL, INIT_VOL, sum); | ||
967 | |||
968 | return 0; | ||
969 | } | ||
970 | |||
971 | static int mixer_set_input_port(struct amixer *amixer, struct rsc *rsc) | ||
972 | { | ||
973 | amixer->ops->set_input(amixer, rsc); | ||
974 | amixer->ops->commit_write(amixer); | ||
975 | |||
976 | return 0; | ||
977 | } | ||
978 | |||
979 | static enum CT_AMIXER_CTL port_to_amixer(enum MIXER_PORT_T type) | ||
980 | { | ||
981 | switch (type) { | ||
982 | case MIX_WAVE_FRONT: return AMIXER_WAVE_F; | ||
983 | case MIX_WAVE_SURROUND: return AMIXER_WAVE_S; | ||
984 | case MIX_WAVE_CENTLFE: return AMIXER_WAVE_C; | ||
985 | case MIX_WAVE_REAR: return AMIXER_WAVE_R; | ||
986 | case MIX_PCMO_FRONT: return AMIXER_MASTER_F_C; | ||
987 | case MIX_SPDIF_OUT: return AMIXER_SPDIFO; | ||
988 | case MIX_LINE_IN: return AMIXER_LINEIN; | ||
989 | case MIX_MIC_IN: return AMIXER_MIC; | ||
990 | case MIX_SPDIF_IN: return AMIXER_SPDIFI; | ||
991 | case MIX_PCMI_FRONT: return AMIXER_PCM_F; | ||
992 | case MIX_PCMI_SURROUND: return AMIXER_PCM_S; | ||
993 | case MIX_PCMI_CENTLFE: return AMIXER_PCM_C; | ||
994 | case MIX_PCMI_REAR: return AMIXER_PCM_R; | ||
995 | default: return 0; | ||
996 | } | ||
997 | } | ||
998 | |||
999 | static int mixer_get_output_ports(struct ct_mixer *mixer, | ||
1000 | enum MIXER_PORT_T type, | ||
1001 | struct rsc **rleft, struct rsc **rright) | ||
1002 | { | ||
1003 | enum CT_AMIXER_CTL amix = port_to_amixer(type); | ||
1004 | |||
1005 | if (NULL != rleft) | ||
1006 | *rleft = &((struct amixer *)mixer->amixers[amix*CHN_NUM])->rsc; | ||
1007 | |||
1008 | if (NULL != rright) | ||
1009 | *rright = | ||
1010 | &((struct amixer *)mixer->amixers[amix*CHN_NUM+1])->rsc; | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | |||
1015 | static int mixer_set_input_left(struct ct_mixer *mixer, | ||
1016 | enum MIXER_PORT_T type, struct rsc *rsc) | ||
1017 | { | ||
1018 | enum CT_AMIXER_CTL amix = port_to_amixer(type); | ||
1019 | |||
1020 | mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc); | ||
1021 | amix = get_recording_amixer(amix); | ||
1022 | if (amix < NUM_CT_AMIXERS) | ||
1023 | mixer_set_input_port(mixer->amixers[amix*CHN_NUM], rsc); | ||
1024 | |||
1025 | return 0; | ||
1026 | } | ||
1027 | |||
1028 | static int | ||
1029 | mixer_set_input_right(struct ct_mixer *mixer, | ||
1030 | enum MIXER_PORT_T type, struct rsc *rsc) | ||
1031 | { | ||
1032 | enum CT_AMIXER_CTL amix = port_to_amixer(type); | ||
1033 | |||
1034 | mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc); | ||
1035 | amix = get_recording_amixer(amix); | ||
1036 | if (amix < NUM_CT_AMIXERS) | ||
1037 | mixer_set_input_port(mixer->amixers[amix*CHN_NUM+1], rsc); | ||
1038 | |||
1039 | return 0; | ||
1040 | } | ||
1041 | |||
1042 | int ct_mixer_destroy(struct ct_mixer *mixer) | ||
1043 | { | ||
1044 | struct sum_mgr *sum_mgr = (struct sum_mgr *)mixer->atc->rsc_mgrs[SUM]; | ||
1045 | struct amixer_mgr *amixer_mgr = | ||
1046 | (struct amixer_mgr *)mixer->atc->rsc_mgrs[AMIXER]; | ||
1047 | struct amixer *amixer; | ||
1048 | int i = 0; | ||
1049 | |||
1050 | /* Release amixer resources */ | ||
1051 | for (i = 0; i < (NUM_CT_AMIXERS * CHN_NUM); i++) { | ||
1052 | if (NULL != mixer->amixers[i]) { | ||
1053 | amixer = mixer->amixers[i]; | ||
1054 | amixer_mgr->put_amixer(amixer_mgr, amixer); | ||
1055 | } | ||
1056 | } | ||
1057 | |||
1058 | /* Release sum resources */ | ||
1059 | for (i = 0; i < (NUM_CT_SUMS * CHN_NUM); i++) { | ||
1060 | if (NULL != mixer->sums[i]) | ||
1061 | sum_mgr->put_sum(sum_mgr, (struct sum *)mixer->sums[i]); | ||
1062 | } | ||
1063 | |||
1064 | /* Release mem assigned to mixer object */ | ||
1065 | kfree(mixer->sums); | ||
1066 | kfree(mixer->amixers); | ||
1067 | kfree(mixer); | ||
1068 | |||
1069 | return 0; | ||
1070 | } | ||
1071 | |||
1072 | int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer) | ||
1073 | { | ||
1074 | struct ct_mixer *mixer; | ||
1075 | int err; | ||
1076 | |||
1077 | *rmixer = NULL; | ||
1078 | |||
1079 | /* Allocate mem for mixer obj */ | ||
1080 | err = ct_mixer_get_mem(&mixer); | ||
1081 | if (err) | ||
1082 | return err; | ||
1083 | |||
1084 | mixer->switch_state = 0; | ||
1085 | mixer->atc = atc; | ||
1086 | /* Set operations */ | ||
1087 | mixer->get_output_ports = mixer_get_output_ports; | ||
1088 | mixer->set_input_left = mixer_set_input_left; | ||
1089 | mixer->set_input_right = mixer_set_input_right; | ||
1090 | |||
1091 | /* Allocate chip resources for mixer obj */ | ||
1092 | err = ct_mixer_get_resources(mixer); | ||
1093 | if (err) | ||
1094 | goto error; | ||
1095 | |||
1096 | /* Build internal mixer topology */ | ||
1097 | ct_mixer_topology_build(mixer); | ||
1098 | |||
1099 | *rmixer = mixer; | ||
1100 | |||
1101 | return 0; | ||
1102 | |||
1103 | error: | ||
1104 | ct_mixer_destroy(mixer); | ||
1105 | return err; | ||
1106 | } | ||
1107 | |||
1108 | int ct_alsa_mix_create(struct ct_atc *atc, | ||
1109 | enum CTALSADEVS device, | ||
1110 | const char *device_name) | ||
1111 | { | ||
1112 | int err; | ||
1113 | |||
1114 | /* Create snd kcontrol instances on demand */ | ||
1115 | /* vol_ctl.device = swh_ctl.device = device; */ /* better w/ device 0 */ | ||
1116 | err = ct_mixer_kcontrols_create((struct ct_mixer *)atc->mixer); | ||
1117 | if (err) | ||
1118 | return err; | ||
1119 | |||
1120 | strcpy(atc->card->mixername, device_name); | ||
1121 | |||
1122 | return 0; | ||
1123 | } | ||
diff --git a/sound/pci/ctxfi/ctmixer.h b/sound/pci/ctxfi/ctmixer.h new file mode 100644 index 000000000000..e2d96ebde746 --- /dev/null +++ b/sound/pci/ctxfi/ctmixer.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctmixer.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of the mixer device functions. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date Mar 28 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef CTMIXER_H | ||
19 | #define CTMIXER_H | ||
20 | |||
21 | #include "ctatc.h" | ||
22 | #include "ctresource.h" | ||
23 | |||
24 | #define INIT_VOL 0x1c00 | ||
25 | |||
26 | enum MIXER_PORT_T { | ||
27 | MIX_WAVE_FRONT, | ||
28 | MIX_WAVE_REAR, | ||
29 | MIX_WAVE_CENTLFE, | ||
30 | MIX_WAVE_SURROUND, | ||
31 | MIX_SPDIF_OUT, | ||
32 | MIX_PCMO_FRONT, | ||
33 | MIX_MIC_IN, | ||
34 | MIX_LINE_IN, | ||
35 | MIX_SPDIF_IN, | ||
36 | MIX_PCMI_FRONT, | ||
37 | MIX_PCMI_REAR, | ||
38 | MIX_PCMI_CENTLFE, | ||
39 | MIX_PCMI_SURROUND, | ||
40 | |||
41 | NUM_MIX_PORTS | ||
42 | }; | ||
43 | |||
44 | /* alsa mixer descriptor */ | ||
45 | struct ct_mixer { | ||
46 | struct ct_atc *atc; | ||
47 | |||
48 | void **amixers; /* amixer resources for volume control */ | ||
49 | void **sums; /* sum resources for signal collection */ | ||
50 | unsigned int switch_state; /* A bit-map to indicate state of switches */ | ||
51 | |||
52 | int (*get_output_ports)(struct ct_mixer *mixer, enum MIXER_PORT_T type, | ||
53 | struct rsc **rleft, struct rsc **rright); | ||
54 | |||
55 | int (*set_input_left)(struct ct_mixer *mixer, | ||
56 | enum MIXER_PORT_T type, struct rsc *rsc); | ||
57 | int (*set_input_right)(struct ct_mixer *mixer, | ||
58 | enum MIXER_PORT_T type, struct rsc *rsc); | ||
59 | }; | ||
60 | |||
61 | int ct_alsa_mix_create(struct ct_atc *atc, | ||
62 | enum CTALSADEVS device, | ||
63 | const char *device_name); | ||
64 | int ct_mixer_create(struct ct_atc *atc, struct ct_mixer **rmixer); | ||
65 | int ct_mixer_destroy(struct ct_mixer *mixer); | ||
66 | |||
67 | #endif /* CTMIXER_H */ | ||
diff --git a/sound/pci/ctxfi/ctpcm.c b/sound/pci/ctxfi/ctpcm.c new file mode 100644 index 000000000000..9e5c0c4da726 --- /dev/null +++ b/sound/pci/ctxfi/ctpcm.c | |||
@@ -0,0 +1,426 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctpcm.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of the pcm device functions. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date Apr 2 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include "ctpcm.h" | ||
19 | #include "cttimer.h" | ||
20 | #include <sound/pcm.h> | ||
21 | |||
22 | /* Hardware descriptions for playback */ | ||
23 | static struct snd_pcm_hardware ct_pcm_playback_hw = { | ||
24 | .info = (SNDRV_PCM_INFO_MMAP | | ||
25 | SNDRV_PCM_INFO_INTERLEAVED | | ||
26 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
27 | SNDRV_PCM_INFO_MMAP_VALID | | ||
28 | SNDRV_PCM_INFO_PAUSE), | ||
29 | .formats = (SNDRV_PCM_FMTBIT_U8 | | ||
30 | SNDRV_PCM_FMTBIT_S16_LE | | ||
31 | SNDRV_PCM_FMTBIT_S24_3LE | | ||
32 | SNDRV_PCM_FMTBIT_S32_LE | | ||
33 | SNDRV_PCM_FMTBIT_FLOAT_LE), | ||
34 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
35 | SNDRV_PCM_RATE_8000_192000), | ||
36 | .rate_min = 8000, | ||
37 | .rate_max = 192000, | ||
38 | .channels_min = 1, | ||
39 | .channels_max = 2, | ||
40 | .buffer_bytes_max = (128*1024), | ||
41 | .period_bytes_min = (64), | ||
42 | .period_bytes_max = (128*1024), | ||
43 | .periods_min = 2, | ||
44 | .periods_max = 1024, | ||
45 | .fifo_size = 0, | ||
46 | }; | ||
47 | |||
48 | static struct snd_pcm_hardware ct_spdif_passthru_playback_hw = { | ||
49 | .info = (SNDRV_PCM_INFO_MMAP | | ||
50 | SNDRV_PCM_INFO_INTERLEAVED | | ||
51 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
52 | SNDRV_PCM_INFO_MMAP_VALID | | ||
53 | SNDRV_PCM_INFO_PAUSE), | ||
54 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
55 | .rates = (SNDRV_PCM_RATE_48000 | | ||
56 | SNDRV_PCM_RATE_44100 | | ||
57 | SNDRV_PCM_RATE_32000), | ||
58 | .rate_min = 32000, | ||
59 | .rate_max = 48000, | ||
60 | .channels_min = 2, | ||
61 | .channels_max = 2, | ||
62 | .buffer_bytes_max = (128*1024), | ||
63 | .period_bytes_min = (64), | ||
64 | .period_bytes_max = (128*1024), | ||
65 | .periods_min = 2, | ||
66 | .periods_max = 1024, | ||
67 | .fifo_size = 0, | ||
68 | }; | ||
69 | |||
70 | /* Hardware descriptions for capture */ | ||
71 | static struct snd_pcm_hardware ct_pcm_capture_hw = { | ||
72 | .info = (SNDRV_PCM_INFO_MMAP | | ||
73 | SNDRV_PCM_INFO_INTERLEAVED | | ||
74 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | ||
75 | SNDRV_PCM_INFO_PAUSE | | ||
76 | SNDRV_PCM_INFO_MMAP_VALID), | ||
77 | .formats = (SNDRV_PCM_FMTBIT_U8 | | ||
78 | SNDRV_PCM_FMTBIT_S16_LE | | ||
79 | SNDRV_PCM_FMTBIT_S24_3LE | | ||
80 | SNDRV_PCM_FMTBIT_S32_LE | | ||
81 | SNDRV_PCM_FMTBIT_FLOAT_LE), | ||
82 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
83 | SNDRV_PCM_RATE_8000_96000), | ||
84 | .rate_min = 8000, | ||
85 | .rate_max = 96000, | ||
86 | .channels_min = 1, | ||
87 | .channels_max = 2, | ||
88 | .buffer_bytes_max = (128*1024), | ||
89 | .period_bytes_min = (384), | ||
90 | .period_bytes_max = (64*1024), | ||
91 | .periods_min = 2, | ||
92 | .periods_max = 1024, | ||
93 | .fifo_size = 0, | ||
94 | }; | ||
95 | |||
96 | static void ct_atc_pcm_interrupt(struct ct_atc_pcm *atc_pcm) | ||
97 | { | ||
98 | struct ct_atc_pcm *apcm = atc_pcm; | ||
99 | |||
100 | if (NULL == apcm->substream) | ||
101 | return; | ||
102 | |||
103 | snd_pcm_period_elapsed(apcm->substream); | ||
104 | } | ||
105 | |||
106 | static void ct_atc_pcm_free_substream(struct snd_pcm_runtime *runtime) | ||
107 | { | ||
108 | struct ct_atc_pcm *apcm = runtime->private_data; | ||
109 | struct ct_atc *atc = snd_pcm_substream_chip(apcm->substream); | ||
110 | |||
111 | atc->pcm_release_resources(atc, apcm); | ||
112 | ct_timer_instance_free(apcm->timer); | ||
113 | kfree(apcm); | ||
114 | runtime->private_data = NULL; | ||
115 | } | ||
116 | |||
117 | /* pcm playback operations */ | ||
118 | static int ct_pcm_playback_open(struct snd_pcm_substream *substream) | ||
119 | { | ||
120 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
121 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
122 | struct ct_atc_pcm *apcm; | ||
123 | int err; | ||
124 | |||
125 | apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); | ||
126 | if (NULL == apcm) | ||
127 | return -ENOMEM; | ||
128 | |||
129 | apcm->substream = substream; | ||
130 | apcm->interrupt = ct_atc_pcm_interrupt; | ||
131 | runtime->private_data = apcm; | ||
132 | runtime->private_free = ct_atc_pcm_free_substream; | ||
133 | if (IEC958 == substream->pcm->device) { | ||
134 | runtime->hw = ct_spdif_passthru_playback_hw; | ||
135 | atc->spdif_out_passthru(atc, 1); | ||
136 | } else { | ||
137 | runtime->hw = ct_pcm_playback_hw; | ||
138 | if (FRONT == substream->pcm->device) | ||
139 | runtime->hw.channels_max = 8; | ||
140 | } | ||
141 | |||
142 | err = snd_pcm_hw_constraint_integer(runtime, | ||
143 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
144 | if (err < 0) { | ||
145 | kfree(apcm); | ||
146 | return err; | ||
147 | } | ||
148 | err = snd_pcm_hw_constraint_minmax(runtime, | ||
149 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
150 | 1024, UINT_MAX); | ||
151 | if (err < 0) { | ||
152 | kfree(apcm); | ||
153 | return err; | ||
154 | } | ||
155 | |||
156 | apcm->timer = ct_timer_instance_new(atc->timer, apcm); | ||
157 | if (!apcm->timer) | ||
158 | return -ENOMEM; | ||
159 | |||
160 | return 0; | ||
161 | } | ||
162 | |||
163 | static int ct_pcm_playback_close(struct snd_pcm_substream *substream) | ||
164 | { | ||
165 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
166 | |||
167 | /* TODO: Notify mixer inactive. */ | ||
168 | if (IEC958 == substream->pcm->device) | ||
169 | atc->spdif_out_passthru(atc, 0); | ||
170 | |||
171 | /* The ct_atc_pcm object will be freed by runtime->private_free */ | ||
172 | |||
173 | return 0; | ||
174 | } | ||
175 | |||
176 | static int ct_pcm_hw_params(struct snd_pcm_substream *substream, | ||
177 | struct snd_pcm_hw_params *hw_params) | ||
178 | { | ||
179 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
180 | struct ct_atc_pcm *apcm = substream->runtime->private_data; | ||
181 | int err; | ||
182 | |||
183 | err = snd_pcm_lib_malloc_pages(substream, | ||
184 | params_buffer_bytes(hw_params)); | ||
185 | if (err < 0) | ||
186 | return err; | ||
187 | /* clear previous resources */ | ||
188 | atc->pcm_release_resources(atc, apcm); | ||
189 | return err; | ||
190 | } | ||
191 | |||
192 | static int ct_pcm_hw_free(struct snd_pcm_substream *substream) | ||
193 | { | ||
194 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
195 | struct ct_atc_pcm *apcm = substream->runtime->private_data; | ||
196 | |||
197 | /* clear previous resources */ | ||
198 | atc->pcm_release_resources(atc, apcm); | ||
199 | /* Free snd-allocated pages */ | ||
200 | return snd_pcm_lib_free_pages(substream); | ||
201 | } | ||
202 | |||
203 | |||
204 | static int ct_pcm_playback_prepare(struct snd_pcm_substream *substream) | ||
205 | { | ||
206 | int err; | ||
207 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
208 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
209 | struct ct_atc_pcm *apcm = runtime->private_data; | ||
210 | |||
211 | if (IEC958 == substream->pcm->device) | ||
212 | err = atc->spdif_passthru_playback_prepare(atc, apcm); | ||
213 | else | ||
214 | err = atc->pcm_playback_prepare(atc, apcm); | ||
215 | |||
216 | if (err < 0) { | ||
217 | printk(KERN_ERR "ctxfi: Preparing pcm playback failed!!!\n"); | ||
218 | return err; | ||
219 | } | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static int | ||
225 | ct_pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd) | ||
226 | { | ||
227 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
228 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
229 | struct ct_atc_pcm *apcm = runtime->private_data; | ||
230 | |||
231 | switch (cmd) { | ||
232 | case SNDRV_PCM_TRIGGER_START: | ||
233 | case SNDRV_PCM_TRIGGER_RESUME: | ||
234 | case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: | ||
235 | atc->pcm_playback_start(atc, apcm); | ||
236 | break; | ||
237 | case SNDRV_PCM_TRIGGER_STOP: | ||
238 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
239 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | ||
240 | atc->pcm_playback_stop(atc, apcm); | ||
241 | break; | ||
242 | default: | ||
243 | break; | ||
244 | } | ||
245 | |||
246 | return 0; | ||
247 | } | ||
248 | |||
249 | static snd_pcm_uframes_t | ||
250 | ct_pcm_playback_pointer(struct snd_pcm_substream *substream) | ||
251 | { | ||
252 | unsigned long position; | ||
253 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
254 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
255 | struct ct_atc_pcm *apcm = runtime->private_data; | ||
256 | |||
257 | /* Read out playback position */ | ||
258 | position = atc->pcm_playback_position(atc, apcm); | ||
259 | position = bytes_to_frames(runtime, position); | ||
260 | if (position >= runtime->buffer_size) | ||
261 | position = 0; | ||
262 | return position; | ||
263 | } | ||
264 | |||
265 | /* pcm capture operations */ | ||
266 | static int ct_pcm_capture_open(struct snd_pcm_substream *substream) | ||
267 | { | ||
268 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
269 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
270 | struct ct_atc_pcm *apcm; | ||
271 | int err; | ||
272 | |||
273 | apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); | ||
274 | if (NULL == apcm) | ||
275 | return -ENOMEM; | ||
276 | |||
277 | apcm->started = 0; | ||
278 | apcm->substream = substream; | ||
279 | apcm->interrupt = ct_atc_pcm_interrupt; | ||
280 | runtime->private_data = apcm; | ||
281 | runtime->private_free = ct_atc_pcm_free_substream; | ||
282 | runtime->hw = ct_pcm_capture_hw; | ||
283 | runtime->hw.rate_max = atc->rsr * atc->msr; | ||
284 | |||
285 | err = snd_pcm_hw_constraint_integer(runtime, | ||
286 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
287 | if (err < 0) { | ||
288 | kfree(apcm); | ||
289 | return err; | ||
290 | } | ||
291 | err = snd_pcm_hw_constraint_minmax(runtime, | ||
292 | SNDRV_PCM_HW_PARAM_BUFFER_BYTES, | ||
293 | 1024, UINT_MAX); | ||
294 | if (err < 0) { | ||
295 | kfree(apcm); | ||
296 | return err; | ||
297 | } | ||
298 | |||
299 | apcm->timer = ct_timer_instance_new(atc->timer, apcm); | ||
300 | if (!apcm->timer) | ||
301 | return -ENOMEM; | ||
302 | |||
303 | return 0; | ||
304 | } | ||
305 | |||
306 | static int ct_pcm_capture_close(struct snd_pcm_substream *substream) | ||
307 | { | ||
308 | /* The ct_atc_pcm object will be freed by runtime->private_free */ | ||
309 | /* TODO: Notify mixer inactive. */ | ||
310 | return 0; | ||
311 | } | ||
312 | |||
313 | static int ct_pcm_capture_prepare(struct snd_pcm_substream *substream) | ||
314 | { | ||
315 | int err; | ||
316 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
317 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
318 | struct ct_atc_pcm *apcm = runtime->private_data; | ||
319 | |||
320 | err = atc->pcm_capture_prepare(atc, apcm); | ||
321 | if (err < 0) { | ||
322 | printk(KERN_ERR "ctxfi: Preparing pcm capture failed!!!\n"); | ||
323 | return err; | ||
324 | } | ||
325 | |||
326 | return 0; | ||
327 | } | ||
328 | |||
329 | static int | ||
330 | ct_pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd) | ||
331 | { | ||
332 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
333 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
334 | struct ct_atc_pcm *apcm = runtime->private_data; | ||
335 | |||
336 | switch (cmd) { | ||
337 | case SNDRV_PCM_TRIGGER_START: | ||
338 | atc->pcm_capture_start(atc, apcm); | ||
339 | break; | ||
340 | case SNDRV_PCM_TRIGGER_STOP: | ||
341 | atc->pcm_capture_stop(atc, apcm); | ||
342 | break; | ||
343 | default: | ||
344 | atc->pcm_capture_stop(atc, apcm); | ||
345 | break; | ||
346 | } | ||
347 | |||
348 | return 0; | ||
349 | } | ||
350 | |||
351 | static snd_pcm_uframes_t | ||
352 | ct_pcm_capture_pointer(struct snd_pcm_substream *substream) | ||
353 | { | ||
354 | unsigned long position; | ||
355 | struct ct_atc *atc = snd_pcm_substream_chip(substream); | ||
356 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
357 | struct ct_atc_pcm *apcm = runtime->private_data; | ||
358 | |||
359 | /* Read out playback position */ | ||
360 | position = atc->pcm_capture_position(atc, apcm); | ||
361 | position = bytes_to_frames(runtime, position); | ||
362 | if (position >= runtime->buffer_size) | ||
363 | position = 0; | ||
364 | return position; | ||
365 | } | ||
366 | |||
367 | /* PCM operators for playback */ | ||
368 | static struct snd_pcm_ops ct_pcm_playback_ops = { | ||
369 | .open = ct_pcm_playback_open, | ||
370 | .close = ct_pcm_playback_close, | ||
371 | .ioctl = snd_pcm_lib_ioctl, | ||
372 | .hw_params = ct_pcm_hw_params, | ||
373 | .hw_free = ct_pcm_hw_free, | ||
374 | .prepare = ct_pcm_playback_prepare, | ||
375 | .trigger = ct_pcm_playback_trigger, | ||
376 | .pointer = ct_pcm_playback_pointer, | ||
377 | .page = snd_pcm_sgbuf_ops_page, | ||
378 | }; | ||
379 | |||
380 | /* PCM operators for capture */ | ||
381 | static struct snd_pcm_ops ct_pcm_capture_ops = { | ||
382 | .open = ct_pcm_capture_open, | ||
383 | .close = ct_pcm_capture_close, | ||
384 | .ioctl = snd_pcm_lib_ioctl, | ||
385 | .hw_params = ct_pcm_hw_params, | ||
386 | .hw_free = ct_pcm_hw_free, | ||
387 | .prepare = ct_pcm_capture_prepare, | ||
388 | .trigger = ct_pcm_capture_trigger, | ||
389 | .pointer = ct_pcm_capture_pointer, | ||
390 | .page = snd_pcm_sgbuf_ops_page, | ||
391 | }; | ||
392 | |||
393 | /* Create ALSA pcm device */ | ||
394 | int ct_alsa_pcm_create(struct ct_atc *atc, | ||
395 | enum CTALSADEVS device, | ||
396 | const char *device_name) | ||
397 | { | ||
398 | struct snd_pcm *pcm; | ||
399 | int err; | ||
400 | int playback_count, capture_count; | ||
401 | |||
402 | playback_count = (IEC958 == device) ? 1 : 8; | ||
403 | capture_count = (FRONT == device) ? 1 : 0; | ||
404 | err = snd_pcm_new(atc->card, "ctxfi", device, | ||
405 | playback_count, capture_count, &pcm); | ||
406 | if (err < 0) { | ||
407 | printk(KERN_ERR "ctxfi: snd_pcm_new failed!! Err=%d\n", err); | ||
408 | return err; | ||
409 | } | ||
410 | |||
411 | pcm->private_data = atc; | ||
412 | pcm->info_flags = 0; | ||
413 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | ||
414 | strlcpy(pcm->name, device_name, sizeof(pcm->name)); | ||
415 | |||
416 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ct_pcm_playback_ops); | ||
417 | |||
418 | if (FRONT == device) | ||
419 | snd_pcm_set_ops(pcm, | ||
420 | SNDRV_PCM_STREAM_CAPTURE, &ct_pcm_capture_ops); | ||
421 | |||
422 | snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV_SG, | ||
423 | snd_dma_pci_data(atc->pci), 128*1024, 128*1024); | ||
424 | |||
425 | return 0; | ||
426 | } | ||
diff --git a/sound/pci/ctxfi/ctpcm.h b/sound/pci/ctxfi/ctpcm.h new file mode 100644 index 000000000000..178da0dca647 --- /dev/null +++ b/sound/pci/ctxfi/ctpcm.h | |||
@@ -0,0 +1,27 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctpcm.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of the pcm device functions. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date Mar 28 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #ifndef CTPCM_H | ||
19 | #define CTPCM_H | ||
20 | |||
21 | #include "ctatc.h" | ||
22 | |||
23 | int ct_alsa_pcm_create(struct ct_atc *atc, | ||
24 | enum CTALSADEVS device, | ||
25 | const char *device_name); | ||
26 | |||
27 | #endif /* CTPCM_H */ | ||
diff --git a/sound/pci/ctxfi/ctresource.c b/sound/pci/ctxfi/ctresource.c new file mode 100644 index 000000000000..889c495bb7d1 --- /dev/null +++ b/sound/pci/ctxfi/ctresource.c | |||
@@ -0,0 +1,301 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctresource.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of some generic helper functions. | ||
12 | * | ||
13 | * @Author Liu Chun | ||
14 | * @Date May 15 2008 | ||
15 | * | ||
16 | */ | ||
17 | |||
18 | #include "ctresource.h" | ||
19 | #include "cthardware.h" | ||
20 | #include <linux/err.h> | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #define AUDIO_SLOT_BLOCK_NUM 256 | ||
24 | |||
25 | /* Resource allocation based on bit-map management mechanism */ | ||
26 | static int | ||
27 | get_resource(u8 *rscs, unsigned int amount, | ||
28 | unsigned int multi, unsigned int *ridx) | ||
29 | { | ||
30 | int i, j, k, n; | ||
31 | |||
32 | /* Check whether there are sufficient resources to meet request. */ | ||
33 | for (i = 0, n = multi; i < amount; i++) { | ||
34 | j = i / 8; | ||
35 | k = i % 8; | ||
36 | if (rscs[j] & ((u8)1 << k)) { | ||
37 | n = multi; | ||
38 | continue; | ||
39 | } | ||
40 | if (!(--n)) | ||
41 | break; /* found sufficient contiguous resources */ | ||
42 | } | ||
43 | |||
44 | if (i >= amount) { | ||
45 | /* Can not find sufficient contiguous resources */ | ||
46 | return -ENOENT; | ||
47 | } | ||
48 | |||
49 | /* Mark the contiguous bits in resource bit-map as used */ | ||
50 | for (n = multi; n > 0; n--) { | ||
51 | j = i / 8; | ||
52 | k = i % 8; | ||
53 | rscs[j] |= ((u8)1 << k); | ||
54 | i--; | ||
55 | } | ||
56 | |||
57 | *ridx = i + 1; | ||
58 | |||
59 | return 0; | ||
60 | } | ||
61 | |||
62 | static int put_resource(u8 *rscs, unsigned int multi, unsigned int idx) | ||
63 | { | ||
64 | unsigned int i, j, k, n; | ||
65 | |||
66 | /* Mark the contiguous bits in resource bit-map as used */ | ||
67 | for (n = multi, i = idx; n > 0; n--) { | ||
68 | j = i / 8; | ||
69 | k = i % 8; | ||
70 | rscs[j] &= ~((u8)1 << k); | ||
71 | i++; | ||
72 | } | ||
73 | |||
74 | return 0; | ||
75 | } | ||
76 | |||
77 | int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx) | ||
78 | { | ||
79 | int err; | ||
80 | |||
81 | if (n > mgr->avail) | ||
82 | return -ENOENT; | ||
83 | |||
84 | err = get_resource(mgr->rscs, mgr->amount, n, ridx); | ||
85 | if (!err) | ||
86 | mgr->avail -= n; | ||
87 | |||
88 | return err; | ||
89 | } | ||
90 | |||
91 | int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx) | ||
92 | { | ||
93 | put_resource(mgr->rscs, n, idx); | ||
94 | mgr->avail += n; | ||
95 | |||
96 | return 0; | ||
97 | } | ||
98 | |||
99 | static unsigned char offset_in_audio_slot_block[NUM_RSCTYP] = { | ||
100 | /* SRC channel is at Audio Ring slot 1 every 16 slots. */ | ||
101 | [SRC] = 0x1, | ||
102 | [AMIXER] = 0x4, | ||
103 | [SUM] = 0xc, | ||
104 | }; | ||
105 | |||
106 | static int rsc_index(const struct rsc *rsc) | ||
107 | { | ||
108 | return rsc->conj; | ||
109 | } | ||
110 | |||
111 | static int audio_ring_slot(const struct rsc *rsc) | ||
112 | { | ||
113 | return (rsc->conj << 4) + offset_in_audio_slot_block[rsc->type]; | ||
114 | } | ||
115 | |||
116 | static int rsc_next_conj(struct rsc *rsc) | ||
117 | { | ||
118 | unsigned int i; | ||
119 | for (i = 0; (i < 8) && (!(rsc->msr & (0x1 << i))); ) | ||
120 | i++; | ||
121 | rsc->conj += (AUDIO_SLOT_BLOCK_NUM >> i); | ||
122 | return rsc->conj; | ||
123 | } | ||
124 | |||
125 | static int rsc_master(struct rsc *rsc) | ||
126 | { | ||
127 | return rsc->conj = rsc->idx; | ||
128 | } | ||
129 | |||
130 | static struct rsc_ops rsc_generic_ops = { | ||
131 | .index = rsc_index, | ||
132 | .output_slot = audio_ring_slot, | ||
133 | .master = rsc_master, | ||
134 | .next_conj = rsc_next_conj, | ||
135 | }; | ||
136 | |||
137 | int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw) | ||
138 | { | ||
139 | int err = 0; | ||
140 | |||
141 | rsc->idx = idx; | ||
142 | rsc->conj = idx; | ||
143 | rsc->type = type; | ||
144 | rsc->msr = msr; | ||
145 | rsc->hw = hw; | ||
146 | rsc->ops = &rsc_generic_ops; | ||
147 | if (NULL == hw) { | ||
148 | rsc->ctrl_blk = NULL; | ||
149 | return 0; | ||
150 | } | ||
151 | |||
152 | switch (type) { | ||
153 | case SRC: | ||
154 | err = ((struct hw *)hw)->src_rsc_get_ctrl_blk(&rsc->ctrl_blk); | ||
155 | break; | ||
156 | case AMIXER: | ||
157 | err = ((struct hw *)hw)-> | ||
158 | amixer_rsc_get_ctrl_blk(&rsc->ctrl_blk); | ||
159 | break; | ||
160 | case SRCIMP: | ||
161 | case SUM: | ||
162 | case DAIO: | ||
163 | break; | ||
164 | default: | ||
165 | printk(KERN_ERR | ||
166 | "ctxfi: Invalid resource type value %d!\n", type); | ||
167 | return -EINVAL; | ||
168 | } | ||
169 | |||
170 | if (err) { | ||
171 | printk(KERN_ERR | ||
172 | "ctxfi: Failed to get resource control block!\n"); | ||
173 | return err; | ||
174 | } | ||
175 | |||
176 | return 0; | ||
177 | } | ||
178 | |||
179 | int rsc_uninit(struct rsc *rsc) | ||
180 | { | ||
181 | if ((NULL != rsc->hw) && (NULL != rsc->ctrl_blk)) { | ||
182 | switch (rsc->type) { | ||
183 | case SRC: | ||
184 | ((struct hw *)rsc->hw)-> | ||
185 | src_rsc_put_ctrl_blk(rsc->ctrl_blk); | ||
186 | break; | ||
187 | case AMIXER: | ||
188 | ((struct hw *)rsc->hw)-> | ||
189 | amixer_rsc_put_ctrl_blk(rsc->ctrl_blk); | ||
190 | break; | ||
191 | case SUM: | ||
192 | case DAIO: | ||
193 | break; | ||
194 | default: | ||
195 | printk(KERN_ERR "ctxfi: " | ||
196 | "Invalid resource type value %d!\n", rsc->type); | ||
197 | break; | ||
198 | } | ||
199 | |||
200 | rsc->hw = rsc->ctrl_blk = NULL; | ||
201 | } | ||
202 | |||
203 | rsc->idx = rsc->conj = 0; | ||
204 | rsc->type = NUM_RSCTYP; | ||
205 | rsc->msr = 0; | ||
206 | |||
207 | return 0; | ||
208 | } | ||
209 | |||
210 | int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, | ||
211 | unsigned int amount, void *hw_obj) | ||
212 | { | ||
213 | int err = 0; | ||
214 | struct hw *hw = hw_obj; | ||
215 | |||
216 | mgr->type = NUM_RSCTYP; | ||
217 | |||
218 | mgr->rscs = kzalloc(((amount + 8 - 1) / 8), GFP_KERNEL); | ||
219 | if (NULL == mgr->rscs) | ||
220 | return -ENOMEM; | ||
221 | |||
222 | switch (type) { | ||
223 | case SRC: | ||
224 | err = hw->src_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
225 | break; | ||
226 | case SRCIMP: | ||
227 | err = hw->srcimp_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
228 | break; | ||
229 | case AMIXER: | ||
230 | err = hw->amixer_mgr_get_ctrl_blk(&mgr->ctrl_blk); | ||
231 | break; | ||
232 | case DAIO: | ||
233 | err = hw->daio_mgr_get_ctrl_blk(hw, &mgr->ctrl_blk); | ||
234 | break; | ||
235 | case SUM: | ||
236 | break; | ||
237 | default: | ||
238 | printk(KERN_ERR | ||
239 | "ctxfi: Invalid resource type value %d!\n", type); | ||
240 | err = -EINVAL; | ||
241 | goto error; | ||
242 | } | ||
243 | |||
244 | if (err) { | ||
245 | printk(KERN_ERR | ||
246 | "ctxfi: Failed to get manager control block!\n"); | ||
247 | goto error; | ||
248 | } | ||
249 | |||
250 | mgr->type = type; | ||
251 | mgr->avail = mgr->amount = amount; | ||
252 | mgr->hw = hw; | ||
253 | |||
254 | return 0; | ||
255 | |||
256 | error: | ||
257 | kfree(mgr->rscs); | ||
258 | return err; | ||
259 | } | ||
260 | |||
261 | int rsc_mgr_uninit(struct rsc_mgr *mgr) | ||
262 | { | ||
263 | if (NULL != mgr->rscs) { | ||
264 | kfree(mgr->rscs); | ||
265 | mgr->rscs = NULL; | ||
266 | } | ||
267 | |||
268 | if ((NULL != mgr->hw) && (NULL != mgr->ctrl_blk)) { | ||
269 | switch (mgr->type) { | ||
270 | case SRC: | ||
271 | ((struct hw *)mgr->hw)-> | ||
272 | src_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
273 | break; | ||
274 | case SRCIMP: | ||
275 | ((struct hw *)mgr->hw)-> | ||
276 | srcimp_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
277 | break; | ||
278 | case AMIXER: | ||
279 | ((struct hw *)mgr->hw)-> | ||
280 | amixer_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
281 | break; | ||
282 | case DAIO: | ||
283 | ((struct hw *)mgr->hw)-> | ||
284 | daio_mgr_put_ctrl_blk(mgr->ctrl_blk); | ||
285 | break; | ||
286 | case SUM: | ||
287 | break; | ||
288 | default: | ||
289 | printk(KERN_ERR "ctxfi: " | ||
290 | "Invalid resource type value %d!\n", mgr->type); | ||
291 | break; | ||
292 | } | ||
293 | |||
294 | mgr->hw = mgr->ctrl_blk = NULL; | ||
295 | } | ||
296 | |||
297 | mgr->type = NUM_RSCTYP; | ||
298 | mgr->avail = mgr->amount = 0; | ||
299 | |||
300 | return 0; | ||
301 | } | ||
diff --git a/sound/pci/ctxfi/ctresource.h b/sound/pci/ctxfi/ctresource.h new file mode 100644 index 000000000000..0838c2e84f8b --- /dev/null +++ b/sound/pci/ctxfi/ctresource.h | |||
@@ -0,0 +1,72 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctresource.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of generic hardware resources for | ||
12 | * resource management. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 13 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef CTRESOURCE_H | ||
20 | #define CTRESOURCE_H | ||
21 | |||
22 | #include <linux/types.h> | ||
23 | |||
24 | enum RSCTYP { | ||
25 | SRC, | ||
26 | SRCIMP, | ||
27 | AMIXER, | ||
28 | SUM, | ||
29 | DAIO, | ||
30 | NUM_RSCTYP /* This must be the last one and less than 16 */ | ||
31 | }; | ||
32 | |||
33 | struct rsc_ops; | ||
34 | |||
35 | struct rsc { | ||
36 | u32 idx:12; /* The index of a resource */ | ||
37 | u32 type:4; /* The type (RSCTYP) of a resource */ | ||
38 | u32 conj:12; /* Current conjugate index */ | ||
39 | u32 msr:4; /* The Master Sample Rate a resource working on */ | ||
40 | void *ctrl_blk; /* Chip specific control info block for a resource */ | ||
41 | void *hw; /* Chip specific object for hardware access means */ | ||
42 | struct rsc_ops *ops; /* Generic resource operations */ | ||
43 | }; | ||
44 | |||
45 | struct rsc_ops { | ||
46 | int (*master)(struct rsc *rsc); /* Move to master resource */ | ||
47 | int (*next_conj)(struct rsc *rsc); /* Move to next conjugate resource */ | ||
48 | int (*index)(const struct rsc *rsc); /* Return the index of resource */ | ||
49 | /* Return the output slot number */ | ||
50 | int (*output_slot)(const struct rsc *rsc); | ||
51 | }; | ||
52 | |||
53 | int rsc_init(struct rsc *rsc, u32 idx, enum RSCTYP type, u32 msr, void *hw); | ||
54 | int rsc_uninit(struct rsc *rsc); | ||
55 | |||
56 | struct rsc_mgr { | ||
57 | enum RSCTYP type; /* The type (RSCTYP) of resource to manage */ | ||
58 | unsigned int amount; /* The total amount of a kind of resource */ | ||
59 | unsigned int avail; /* The amount of currently available resources */ | ||
60 | unsigned char *rscs; /* The bit-map for resource allocation */ | ||
61 | void *ctrl_blk; /* Chip specific control info block */ | ||
62 | void *hw; /* Chip specific object for hardware access */ | ||
63 | }; | ||
64 | |||
65 | /* Resource management is based on bit-map mechanism */ | ||
66 | int rsc_mgr_init(struct rsc_mgr *mgr, enum RSCTYP type, | ||
67 | unsigned int amount, void *hw); | ||
68 | int rsc_mgr_uninit(struct rsc_mgr *mgr); | ||
69 | int mgr_get_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int *ridx); | ||
70 | int mgr_put_resource(struct rsc_mgr *mgr, unsigned int n, unsigned int idx); | ||
71 | |||
72 | #endif /* CTRESOURCE_H */ | ||
diff --git a/sound/pci/ctxfi/ctsrc.c b/sound/pci/ctxfi/ctsrc.c new file mode 100644 index 000000000000..e1c145d8b702 --- /dev/null +++ b/sound/pci/ctxfi/ctsrc.c | |||
@@ -0,0 +1,886 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctsrc.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of the Sample Rate Convertor | ||
12 | * resource management object. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 13 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #include "ctsrc.h" | ||
20 | #include "cthardware.h" | ||
21 | #include <linux/slab.h> | ||
22 | |||
23 | #define SRC_RESOURCE_NUM 64 | ||
24 | #define SRCIMP_RESOURCE_NUM 256 | ||
25 | |||
26 | static unsigned int conj_mask; | ||
27 | |||
28 | static int src_default_config_memrd(struct src *src); | ||
29 | static int src_default_config_memwr(struct src *src); | ||
30 | static int src_default_config_arcrw(struct src *src); | ||
31 | |||
32 | static int (*src_default_config[3])(struct src *) = { | ||
33 | [MEMRD] = src_default_config_memrd, | ||
34 | [MEMWR] = src_default_config_memwr, | ||
35 | [ARCRW] = src_default_config_arcrw | ||
36 | }; | ||
37 | |||
38 | static int src_set_state(struct src *src, unsigned int state) | ||
39 | { | ||
40 | struct hw *hw; | ||
41 | |||
42 | hw = src->rsc.hw; | ||
43 | hw->src_set_state(src->rsc.ctrl_blk, state); | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | static int src_set_bm(struct src *src, unsigned int bm) | ||
49 | { | ||
50 | struct hw *hw; | ||
51 | |||
52 | hw = src->rsc.hw; | ||
53 | hw->src_set_bm(src->rsc.ctrl_blk, bm); | ||
54 | |||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | static int src_set_sf(struct src *src, unsigned int sf) | ||
59 | { | ||
60 | struct hw *hw; | ||
61 | |||
62 | hw = src->rsc.hw; | ||
63 | hw->src_set_sf(src->rsc.ctrl_blk, sf); | ||
64 | |||
65 | return 0; | ||
66 | } | ||
67 | |||
68 | static int src_set_pm(struct src *src, unsigned int pm) | ||
69 | { | ||
70 | struct hw *hw; | ||
71 | |||
72 | hw = src->rsc.hw; | ||
73 | hw->src_set_pm(src->rsc.ctrl_blk, pm); | ||
74 | |||
75 | return 0; | ||
76 | } | ||
77 | |||
78 | static int src_set_rom(struct src *src, unsigned int rom) | ||
79 | { | ||
80 | struct hw *hw; | ||
81 | |||
82 | hw = src->rsc.hw; | ||
83 | hw->src_set_rom(src->rsc.ctrl_blk, rom); | ||
84 | |||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int src_set_vo(struct src *src, unsigned int vo) | ||
89 | { | ||
90 | struct hw *hw; | ||
91 | |||
92 | hw = src->rsc.hw; | ||
93 | hw->src_set_vo(src->rsc.ctrl_blk, vo); | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | static int src_set_st(struct src *src, unsigned int st) | ||
99 | { | ||
100 | struct hw *hw; | ||
101 | |||
102 | hw = src->rsc.hw; | ||
103 | hw->src_set_st(src->rsc.ctrl_blk, st); | ||
104 | |||
105 | return 0; | ||
106 | } | ||
107 | |||
108 | static int src_set_bp(struct src *src, unsigned int bp) | ||
109 | { | ||
110 | struct hw *hw; | ||
111 | |||
112 | hw = src->rsc.hw; | ||
113 | hw->src_set_bp(src->rsc.ctrl_blk, bp); | ||
114 | |||
115 | return 0; | ||
116 | } | ||
117 | |||
118 | static int src_set_cisz(struct src *src, unsigned int cisz) | ||
119 | { | ||
120 | struct hw *hw; | ||
121 | |||
122 | hw = src->rsc.hw; | ||
123 | hw->src_set_cisz(src->rsc.ctrl_blk, cisz); | ||
124 | |||
125 | return 0; | ||
126 | } | ||
127 | |||
128 | static int src_set_ca(struct src *src, unsigned int ca) | ||
129 | { | ||
130 | struct hw *hw; | ||
131 | |||
132 | hw = src->rsc.hw; | ||
133 | hw->src_set_ca(src->rsc.ctrl_blk, ca); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int src_set_sa(struct src *src, unsigned int sa) | ||
139 | { | ||
140 | struct hw *hw; | ||
141 | |||
142 | hw = src->rsc.hw; | ||
143 | hw->src_set_sa(src->rsc.ctrl_blk, sa); | ||
144 | |||
145 | return 0; | ||
146 | } | ||
147 | |||
148 | static int src_set_la(struct src *src, unsigned int la) | ||
149 | { | ||
150 | struct hw *hw; | ||
151 | |||
152 | hw = src->rsc.hw; | ||
153 | hw->src_set_la(src->rsc.ctrl_blk, la); | ||
154 | |||
155 | return 0; | ||
156 | } | ||
157 | |||
158 | static int src_set_pitch(struct src *src, unsigned int pitch) | ||
159 | { | ||
160 | struct hw *hw; | ||
161 | |||
162 | hw = src->rsc.hw; | ||
163 | hw->src_set_pitch(src->rsc.ctrl_blk, pitch); | ||
164 | |||
165 | return 0; | ||
166 | } | ||
167 | |||
168 | static int src_set_clear_zbufs(struct src *src) | ||
169 | { | ||
170 | struct hw *hw; | ||
171 | |||
172 | hw = src->rsc.hw; | ||
173 | hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); | ||
174 | |||
175 | return 0; | ||
176 | } | ||
177 | |||
178 | static int src_commit_write(struct src *src) | ||
179 | { | ||
180 | struct hw *hw; | ||
181 | int i; | ||
182 | unsigned int dirty = 0; | ||
183 | |||
184 | hw = src->rsc.hw; | ||
185 | src->rsc.ops->master(&src->rsc); | ||
186 | if (src->rsc.msr > 1) { | ||
187 | /* Save dirty flags for conjugate resource programming */ | ||
188 | dirty = hw->src_get_dirty(src->rsc.ctrl_blk) & conj_mask; | ||
189 | } | ||
190 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), | ||
191 | src->rsc.ctrl_blk); | ||
192 | |||
193 | /* Program conjugate parameter mixer resources */ | ||
194 | if (MEMWR == src->mode) | ||
195 | return 0; | ||
196 | |||
197 | for (i = 1; i < src->rsc.msr; i++) { | ||
198 | src->rsc.ops->next_conj(&src->rsc); | ||
199 | hw->src_set_dirty(src->rsc.ctrl_blk, dirty); | ||
200 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), | ||
201 | src->rsc.ctrl_blk); | ||
202 | } | ||
203 | src->rsc.ops->master(&src->rsc); | ||
204 | |||
205 | return 0; | ||
206 | } | ||
207 | |||
208 | static int src_get_ca(struct src *src) | ||
209 | { | ||
210 | struct hw *hw; | ||
211 | |||
212 | hw = src->rsc.hw; | ||
213 | return hw->src_get_ca(hw, src->rsc.ops->index(&src->rsc), | ||
214 | src->rsc.ctrl_blk); | ||
215 | } | ||
216 | |||
217 | static int src_init(struct src *src) | ||
218 | { | ||
219 | src_default_config[src->mode](src); | ||
220 | |||
221 | return 0; | ||
222 | } | ||
223 | |||
224 | static struct src *src_next_interleave(struct src *src) | ||
225 | { | ||
226 | return src->intlv; | ||
227 | } | ||
228 | |||
229 | static int src_default_config_memrd(struct src *src) | ||
230 | { | ||
231 | struct hw *hw = src->rsc.hw; | ||
232 | unsigned int rsr, msr; | ||
233 | |||
234 | hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); | ||
235 | hw->src_set_bm(src->rsc.ctrl_blk, 1); | ||
236 | for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) | ||
237 | rsr++; | ||
238 | |||
239 | hw->src_set_rsr(src->rsc.ctrl_blk, rsr); | ||
240 | hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); | ||
241 | hw->src_set_wr(src->rsc.ctrl_blk, 0); | ||
242 | hw->src_set_pm(src->rsc.ctrl_blk, 0); | ||
243 | hw->src_set_rom(src->rsc.ctrl_blk, 0); | ||
244 | hw->src_set_vo(src->rsc.ctrl_blk, 0); | ||
245 | hw->src_set_st(src->rsc.ctrl_blk, 0); | ||
246 | hw->src_set_ilsz(src->rsc.ctrl_blk, src->multi - 1); | ||
247 | hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); | ||
248 | hw->src_set_sa(src->rsc.ctrl_blk, 0x0); | ||
249 | hw->src_set_la(src->rsc.ctrl_blk, 0x1000); | ||
250 | hw->src_set_ca(src->rsc.ctrl_blk, 0x80); | ||
251 | hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); | ||
252 | hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); | ||
253 | |||
254 | src->rsc.ops->master(&src->rsc); | ||
255 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), | ||
256 | src->rsc.ctrl_blk); | ||
257 | |||
258 | for (msr = 1; msr < src->rsc.msr; msr++) { | ||
259 | src->rsc.ops->next_conj(&src->rsc); | ||
260 | hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); | ||
261 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), | ||
262 | src->rsc.ctrl_blk); | ||
263 | } | ||
264 | src->rsc.ops->master(&src->rsc); | ||
265 | |||
266 | return 0; | ||
267 | } | ||
268 | |||
269 | static int src_default_config_memwr(struct src *src) | ||
270 | { | ||
271 | struct hw *hw = src->rsc.hw; | ||
272 | |||
273 | hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); | ||
274 | hw->src_set_bm(src->rsc.ctrl_blk, 1); | ||
275 | hw->src_set_rsr(src->rsc.ctrl_blk, 0); | ||
276 | hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_S16); | ||
277 | hw->src_set_wr(src->rsc.ctrl_blk, 1); | ||
278 | hw->src_set_pm(src->rsc.ctrl_blk, 0); | ||
279 | hw->src_set_rom(src->rsc.ctrl_blk, 0); | ||
280 | hw->src_set_vo(src->rsc.ctrl_blk, 0); | ||
281 | hw->src_set_st(src->rsc.ctrl_blk, 0); | ||
282 | hw->src_set_ilsz(src->rsc.ctrl_blk, 0); | ||
283 | hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); | ||
284 | hw->src_set_sa(src->rsc.ctrl_blk, 0x0); | ||
285 | hw->src_set_la(src->rsc.ctrl_blk, 0x1000); | ||
286 | hw->src_set_ca(src->rsc.ctrl_blk, 0x80); | ||
287 | hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); | ||
288 | hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); | ||
289 | |||
290 | src->rsc.ops->master(&src->rsc); | ||
291 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), | ||
292 | src->rsc.ctrl_blk); | ||
293 | |||
294 | return 0; | ||
295 | } | ||
296 | |||
297 | static int src_default_config_arcrw(struct src *src) | ||
298 | { | ||
299 | struct hw *hw = src->rsc.hw; | ||
300 | unsigned int rsr, msr; | ||
301 | unsigned int dirty; | ||
302 | |||
303 | hw->src_set_state(src->rsc.ctrl_blk, SRC_STATE_OFF); | ||
304 | hw->src_set_bm(src->rsc.ctrl_blk, 0); | ||
305 | for (rsr = 0, msr = src->rsc.msr; msr > 1; msr >>= 1) | ||
306 | rsr++; | ||
307 | |||
308 | hw->src_set_rsr(src->rsc.ctrl_blk, rsr); | ||
309 | hw->src_set_sf(src->rsc.ctrl_blk, SRC_SF_F32); | ||
310 | hw->src_set_wr(src->rsc.ctrl_blk, 0); | ||
311 | hw->src_set_pm(src->rsc.ctrl_blk, 0); | ||
312 | hw->src_set_rom(src->rsc.ctrl_blk, 0); | ||
313 | hw->src_set_vo(src->rsc.ctrl_blk, 0); | ||
314 | hw->src_set_st(src->rsc.ctrl_blk, 0); | ||
315 | hw->src_set_ilsz(src->rsc.ctrl_blk, 0); | ||
316 | hw->src_set_cisz(src->rsc.ctrl_blk, 0x80); | ||
317 | hw->src_set_sa(src->rsc.ctrl_blk, 0x0); | ||
318 | /*hw->src_set_sa(src->rsc.ctrl_blk, 0x100);*/ | ||
319 | hw->src_set_la(src->rsc.ctrl_blk, 0x1000); | ||
320 | /*hw->src_set_la(src->rsc.ctrl_blk, 0x03ffffe0);*/ | ||
321 | hw->src_set_ca(src->rsc.ctrl_blk, 0x80); | ||
322 | hw->src_set_pitch(src->rsc.ctrl_blk, 0x1000000); | ||
323 | hw->src_set_clear_zbufs(src->rsc.ctrl_blk, 1); | ||
324 | |||
325 | dirty = hw->src_get_dirty(src->rsc.ctrl_blk); | ||
326 | src->rsc.ops->master(&src->rsc); | ||
327 | for (msr = 0; msr < src->rsc.msr; msr++) { | ||
328 | hw->src_set_dirty(src->rsc.ctrl_blk, dirty); | ||
329 | hw->src_commit_write(hw, src->rsc.ops->index(&src->rsc), | ||
330 | src->rsc.ctrl_blk); | ||
331 | src->rsc.ops->next_conj(&src->rsc); | ||
332 | } | ||
333 | src->rsc.ops->master(&src->rsc); | ||
334 | |||
335 | return 0; | ||
336 | } | ||
337 | |||
338 | static struct src_rsc_ops src_rsc_ops = { | ||
339 | .set_state = src_set_state, | ||
340 | .set_bm = src_set_bm, | ||
341 | .set_sf = src_set_sf, | ||
342 | .set_pm = src_set_pm, | ||
343 | .set_rom = src_set_rom, | ||
344 | .set_vo = src_set_vo, | ||
345 | .set_st = src_set_st, | ||
346 | .set_bp = src_set_bp, | ||
347 | .set_cisz = src_set_cisz, | ||
348 | .set_ca = src_set_ca, | ||
349 | .set_sa = src_set_sa, | ||
350 | .set_la = src_set_la, | ||
351 | .set_pitch = src_set_pitch, | ||
352 | .set_clr_zbufs = src_set_clear_zbufs, | ||
353 | .commit_write = src_commit_write, | ||
354 | .get_ca = src_get_ca, | ||
355 | .init = src_init, | ||
356 | .next_interleave = src_next_interleave, | ||
357 | }; | ||
358 | |||
359 | static int | ||
360 | src_rsc_init(struct src *src, u32 idx, | ||
361 | const struct src_desc *desc, struct src_mgr *mgr) | ||
362 | { | ||
363 | int err; | ||
364 | int i, n; | ||
365 | struct src *p; | ||
366 | |||
367 | n = (MEMRD == desc->mode) ? desc->multi : 1; | ||
368 | for (i = 0, p = src; i < n; i++, p++) { | ||
369 | err = rsc_init(&p->rsc, idx + i, SRC, desc->msr, mgr->mgr.hw); | ||
370 | if (err) | ||
371 | goto error1; | ||
372 | |||
373 | /* Initialize src specific rsc operations */ | ||
374 | p->ops = &src_rsc_ops; | ||
375 | p->multi = (0 == i) ? desc->multi : 1; | ||
376 | p->mode = desc->mode; | ||
377 | src_default_config[desc->mode](p); | ||
378 | mgr->src_enable(mgr, p); | ||
379 | p->intlv = p + 1; | ||
380 | } | ||
381 | (--p)->intlv = NULL; /* Set @intlv of the last SRC to NULL */ | ||
382 | |||
383 | mgr->commit_write(mgr); | ||
384 | |||
385 | return 0; | ||
386 | |||
387 | error1: | ||
388 | for (i--, p--; i >= 0; i--, p--) { | ||
389 | mgr->src_disable(mgr, p); | ||
390 | rsc_uninit(&p->rsc); | ||
391 | } | ||
392 | mgr->commit_write(mgr); | ||
393 | return err; | ||
394 | } | ||
395 | |||
396 | static int src_rsc_uninit(struct src *src, struct src_mgr *mgr) | ||
397 | { | ||
398 | int i, n; | ||
399 | struct src *p; | ||
400 | |||
401 | n = (MEMRD == src->mode) ? src->multi : 1; | ||
402 | for (i = 0, p = src; i < n; i++, p++) { | ||
403 | mgr->src_disable(mgr, p); | ||
404 | rsc_uninit(&p->rsc); | ||
405 | p->multi = 0; | ||
406 | p->ops = NULL; | ||
407 | p->mode = NUM_SRCMODES; | ||
408 | p->intlv = NULL; | ||
409 | } | ||
410 | mgr->commit_write(mgr); | ||
411 | |||
412 | return 0; | ||
413 | } | ||
414 | |||
415 | static int | ||
416 | get_src_rsc(struct src_mgr *mgr, const struct src_desc *desc, struct src **rsrc) | ||
417 | { | ||
418 | unsigned int idx = SRC_RESOURCE_NUM; | ||
419 | int err; | ||
420 | struct src *src; | ||
421 | unsigned long flags; | ||
422 | |||
423 | *rsrc = NULL; | ||
424 | |||
425 | /* Check whether there are sufficient src resources to meet request. */ | ||
426 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
427 | if (MEMRD == desc->mode) | ||
428 | err = mgr_get_resource(&mgr->mgr, desc->multi, &idx); | ||
429 | else | ||
430 | err = mgr_get_resource(&mgr->mgr, 1, &idx); | ||
431 | |||
432 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
433 | if (err) { | ||
434 | printk(KERN_ERR "ctxfi: Can't meet SRC resource request!\n"); | ||
435 | return err; | ||
436 | } | ||
437 | |||
438 | /* Allocate mem for master src resource */ | ||
439 | if (MEMRD == desc->mode) | ||
440 | src = kzalloc(sizeof(*src)*desc->multi, GFP_KERNEL); | ||
441 | else | ||
442 | src = kzalloc(sizeof(*src), GFP_KERNEL); | ||
443 | |||
444 | if (NULL == src) { | ||
445 | err = -ENOMEM; | ||
446 | goto error1; | ||
447 | } | ||
448 | |||
449 | err = src_rsc_init(src, idx, desc, mgr); | ||
450 | if (err) | ||
451 | goto error2; | ||
452 | |||
453 | *rsrc = src; | ||
454 | |||
455 | return 0; | ||
456 | |||
457 | error2: | ||
458 | kfree(src); | ||
459 | error1: | ||
460 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
461 | if (MEMRD == desc->mode) | ||
462 | mgr_put_resource(&mgr->mgr, desc->multi, idx); | ||
463 | else | ||
464 | mgr_put_resource(&mgr->mgr, 1, idx); | ||
465 | |||
466 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
467 | return err; | ||
468 | } | ||
469 | |||
470 | static int put_src_rsc(struct src_mgr *mgr, struct src *src) | ||
471 | { | ||
472 | unsigned long flags; | ||
473 | |||
474 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
475 | src->rsc.ops->master(&src->rsc); | ||
476 | if (MEMRD == src->mode) | ||
477 | mgr_put_resource(&mgr->mgr, src->multi, | ||
478 | src->rsc.ops->index(&src->rsc)); | ||
479 | else | ||
480 | mgr_put_resource(&mgr->mgr, 1, src->rsc.ops->index(&src->rsc)); | ||
481 | |||
482 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
483 | src_rsc_uninit(src, mgr); | ||
484 | kfree(src); | ||
485 | |||
486 | return 0; | ||
487 | } | ||
488 | |||
489 | static int src_enable_s(struct src_mgr *mgr, struct src *src) | ||
490 | { | ||
491 | struct hw *hw = mgr->mgr.hw; | ||
492 | int i; | ||
493 | |||
494 | src->rsc.ops->master(&src->rsc); | ||
495 | for (i = 0; i < src->rsc.msr; i++) { | ||
496 | hw->src_mgr_enbs_src(mgr->mgr.ctrl_blk, | ||
497 | src->rsc.ops->index(&src->rsc)); | ||
498 | src->rsc.ops->next_conj(&src->rsc); | ||
499 | } | ||
500 | src->rsc.ops->master(&src->rsc); | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | static int src_enable(struct src_mgr *mgr, struct src *src) | ||
506 | { | ||
507 | struct hw *hw = mgr->mgr.hw; | ||
508 | int i; | ||
509 | |||
510 | src->rsc.ops->master(&src->rsc); | ||
511 | for (i = 0; i < src->rsc.msr; i++) { | ||
512 | hw->src_mgr_enb_src(mgr->mgr.ctrl_blk, | ||
513 | src->rsc.ops->index(&src->rsc)); | ||
514 | src->rsc.ops->next_conj(&src->rsc); | ||
515 | } | ||
516 | src->rsc.ops->master(&src->rsc); | ||
517 | |||
518 | return 0; | ||
519 | } | ||
520 | |||
521 | static int src_disable(struct src_mgr *mgr, struct src *src) | ||
522 | { | ||
523 | struct hw *hw = mgr->mgr.hw; | ||
524 | int i; | ||
525 | |||
526 | src->rsc.ops->master(&src->rsc); | ||
527 | for (i = 0; i < src->rsc.msr; i++) { | ||
528 | hw->src_mgr_dsb_src(mgr->mgr.ctrl_blk, | ||
529 | src->rsc.ops->index(&src->rsc)); | ||
530 | src->rsc.ops->next_conj(&src->rsc); | ||
531 | } | ||
532 | src->rsc.ops->master(&src->rsc); | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | static int src_mgr_commit_write(struct src_mgr *mgr) | ||
538 | { | ||
539 | struct hw *hw = mgr->mgr.hw; | ||
540 | |||
541 | hw->src_mgr_commit_write(hw, mgr->mgr.ctrl_blk); | ||
542 | |||
543 | return 0; | ||
544 | } | ||
545 | |||
546 | int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr) | ||
547 | { | ||
548 | int err, i; | ||
549 | struct src_mgr *src_mgr; | ||
550 | |||
551 | *rsrc_mgr = NULL; | ||
552 | src_mgr = kzalloc(sizeof(*src_mgr), GFP_KERNEL); | ||
553 | if (NULL == src_mgr) | ||
554 | return -ENOMEM; | ||
555 | |||
556 | err = rsc_mgr_init(&src_mgr->mgr, SRC, SRC_RESOURCE_NUM, hw); | ||
557 | if (err) | ||
558 | goto error1; | ||
559 | |||
560 | spin_lock_init(&src_mgr->mgr_lock); | ||
561 | conj_mask = ((struct hw *)hw)->src_dirty_conj_mask(); | ||
562 | |||
563 | src_mgr->get_src = get_src_rsc; | ||
564 | src_mgr->put_src = put_src_rsc; | ||
565 | src_mgr->src_enable_s = src_enable_s; | ||
566 | src_mgr->src_enable = src_enable; | ||
567 | src_mgr->src_disable = src_disable; | ||
568 | src_mgr->commit_write = src_mgr_commit_write; | ||
569 | |||
570 | /* Disable all SRC resources. */ | ||
571 | for (i = 0; i < 256; i++) | ||
572 | ((struct hw *)hw)->src_mgr_dsb_src(src_mgr->mgr.ctrl_blk, i); | ||
573 | |||
574 | ((struct hw *)hw)->src_mgr_commit_write(hw, src_mgr->mgr.ctrl_blk); | ||
575 | |||
576 | *rsrc_mgr = src_mgr; | ||
577 | |||
578 | return 0; | ||
579 | |||
580 | error1: | ||
581 | kfree(src_mgr); | ||
582 | return err; | ||
583 | } | ||
584 | |||
585 | int src_mgr_destroy(struct src_mgr *src_mgr) | ||
586 | { | ||
587 | rsc_mgr_uninit(&src_mgr->mgr); | ||
588 | kfree(src_mgr); | ||
589 | |||
590 | return 0; | ||
591 | } | ||
592 | |||
593 | /* SRCIMP resource manager operations */ | ||
594 | |||
595 | static int srcimp_master(struct rsc *rsc) | ||
596 | { | ||
597 | rsc->conj = 0; | ||
598 | return rsc->idx = container_of(rsc, struct srcimp, rsc)->idx[0]; | ||
599 | } | ||
600 | |||
601 | static int srcimp_next_conj(struct rsc *rsc) | ||
602 | { | ||
603 | rsc->conj++; | ||
604 | return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj]; | ||
605 | } | ||
606 | |||
607 | static int srcimp_index(const struct rsc *rsc) | ||
608 | { | ||
609 | return container_of(rsc, struct srcimp, rsc)->idx[rsc->conj]; | ||
610 | } | ||
611 | |||
612 | static struct rsc_ops srcimp_basic_rsc_ops = { | ||
613 | .master = srcimp_master, | ||
614 | .next_conj = srcimp_next_conj, | ||
615 | .index = srcimp_index, | ||
616 | .output_slot = NULL, | ||
617 | }; | ||
618 | |||
619 | static int srcimp_map(struct srcimp *srcimp, struct src *src, struct rsc *input) | ||
620 | { | ||
621 | struct imapper *entry; | ||
622 | int i; | ||
623 | |||
624 | srcimp->rsc.ops->master(&srcimp->rsc); | ||
625 | src->rsc.ops->master(&src->rsc); | ||
626 | input->ops->master(input); | ||
627 | |||
628 | /* Program master and conjugate resources */ | ||
629 | for (i = 0; i < srcimp->rsc.msr; i++) { | ||
630 | entry = &srcimp->imappers[i]; | ||
631 | entry->slot = input->ops->output_slot(input); | ||
632 | entry->user = src->rsc.ops->index(&src->rsc); | ||
633 | entry->addr = srcimp->rsc.ops->index(&srcimp->rsc); | ||
634 | srcimp->mgr->imap_add(srcimp->mgr, entry); | ||
635 | srcimp->mapped |= (0x1 << i); | ||
636 | |||
637 | srcimp->rsc.ops->next_conj(&srcimp->rsc); | ||
638 | input->ops->next_conj(input); | ||
639 | } | ||
640 | |||
641 | srcimp->rsc.ops->master(&srcimp->rsc); | ||
642 | input->ops->master(input); | ||
643 | |||
644 | return 0; | ||
645 | } | ||
646 | |||
647 | static int srcimp_unmap(struct srcimp *srcimp) | ||
648 | { | ||
649 | int i; | ||
650 | |||
651 | /* Program master and conjugate resources */ | ||
652 | for (i = 0; i < srcimp->rsc.msr; i++) { | ||
653 | if (srcimp->mapped & (0x1 << i)) { | ||
654 | srcimp->mgr->imap_delete(srcimp->mgr, | ||
655 | &srcimp->imappers[i]); | ||
656 | srcimp->mapped &= ~(0x1 << i); | ||
657 | } | ||
658 | } | ||
659 | |||
660 | return 0; | ||
661 | } | ||
662 | |||
663 | static struct srcimp_rsc_ops srcimp_ops = { | ||
664 | .map = srcimp_map, | ||
665 | .unmap = srcimp_unmap | ||
666 | }; | ||
667 | |||
668 | static int srcimp_rsc_init(struct srcimp *srcimp, | ||
669 | const struct srcimp_desc *desc, | ||
670 | struct srcimp_mgr *mgr) | ||
671 | { | ||
672 | int err; | ||
673 | |||
674 | err = rsc_init(&srcimp->rsc, srcimp->idx[0], | ||
675 | SRCIMP, desc->msr, mgr->mgr.hw); | ||
676 | if (err) | ||
677 | return err; | ||
678 | |||
679 | /* Reserve memory for imapper nodes */ | ||
680 | srcimp->imappers = kzalloc(sizeof(struct imapper)*desc->msr, | ||
681 | GFP_KERNEL); | ||
682 | if (NULL == srcimp->imappers) { | ||
683 | err = -ENOMEM; | ||
684 | goto error1; | ||
685 | } | ||
686 | |||
687 | /* Set srcimp specific operations */ | ||
688 | srcimp->rsc.ops = &srcimp_basic_rsc_ops; | ||
689 | srcimp->ops = &srcimp_ops; | ||
690 | srcimp->mgr = mgr; | ||
691 | |||
692 | srcimp->rsc.ops->master(&srcimp->rsc); | ||
693 | |||
694 | return 0; | ||
695 | |||
696 | error1: | ||
697 | rsc_uninit(&srcimp->rsc); | ||
698 | return err; | ||
699 | } | ||
700 | |||
701 | static int srcimp_rsc_uninit(struct srcimp *srcimp) | ||
702 | { | ||
703 | if (NULL != srcimp->imappers) { | ||
704 | kfree(srcimp->imappers); | ||
705 | srcimp->imappers = NULL; | ||
706 | } | ||
707 | srcimp->ops = NULL; | ||
708 | srcimp->mgr = NULL; | ||
709 | rsc_uninit(&srcimp->rsc); | ||
710 | |||
711 | return 0; | ||
712 | } | ||
713 | |||
714 | static int get_srcimp_rsc(struct srcimp_mgr *mgr, | ||
715 | const struct srcimp_desc *desc, | ||
716 | struct srcimp **rsrcimp) | ||
717 | { | ||
718 | int err, i; | ||
719 | unsigned int idx; | ||
720 | struct srcimp *srcimp; | ||
721 | unsigned long flags; | ||
722 | |||
723 | *rsrcimp = NULL; | ||
724 | |||
725 | /* Allocate mem for SRCIMP resource */ | ||
726 | srcimp = kzalloc(sizeof(*srcimp), GFP_KERNEL); | ||
727 | if (NULL == srcimp) { | ||
728 | err = -ENOMEM; | ||
729 | return err; | ||
730 | } | ||
731 | |||
732 | /* Check whether there are sufficient SRCIMP resources. */ | ||
733 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
734 | for (i = 0; i < desc->msr; i++) { | ||
735 | err = mgr_get_resource(&mgr->mgr, 1, &idx); | ||
736 | if (err) | ||
737 | break; | ||
738 | |||
739 | srcimp->idx[i] = idx; | ||
740 | } | ||
741 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
742 | if (err) { | ||
743 | printk(KERN_ERR "ctxfi: Can't meet SRCIMP resource request!\n"); | ||
744 | goto error1; | ||
745 | } | ||
746 | |||
747 | err = srcimp_rsc_init(srcimp, desc, mgr); | ||
748 | if (err) | ||
749 | goto error1; | ||
750 | |||
751 | *rsrcimp = srcimp; | ||
752 | |||
753 | return 0; | ||
754 | |||
755 | error1: | ||
756 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
757 | for (i--; i >= 0; i--) | ||
758 | mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); | ||
759 | |||
760 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
761 | kfree(srcimp); | ||
762 | return err; | ||
763 | } | ||
764 | |||
765 | static int put_srcimp_rsc(struct srcimp_mgr *mgr, struct srcimp *srcimp) | ||
766 | { | ||
767 | unsigned long flags; | ||
768 | int i; | ||
769 | |||
770 | spin_lock_irqsave(&mgr->mgr_lock, flags); | ||
771 | for (i = 0; i < srcimp->rsc.msr; i++) | ||
772 | mgr_put_resource(&mgr->mgr, 1, srcimp->idx[i]); | ||
773 | |||
774 | spin_unlock_irqrestore(&mgr->mgr_lock, flags); | ||
775 | srcimp_rsc_uninit(srcimp); | ||
776 | kfree(srcimp); | ||
777 | |||
778 | return 0; | ||
779 | } | ||
780 | |||
781 | static int srcimp_map_op(void *data, struct imapper *entry) | ||
782 | { | ||
783 | struct rsc_mgr *mgr = &((struct srcimp_mgr *)data)->mgr; | ||
784 | struct hw *hw = mgr->hw; | ||
785 | |||
786 | hw->srcimp_mgr_set_imaparc(mgr->ctrl_blk, entry->slot); | ||
787 | hw->srcimp_mgr_set_imapuser(mgr->ctrl_blk, entry->user); | ||
788 | hw->srcimp_mgr_set_imapnxt(mgr->ctrl_blk, entry->next); | ||
789 | hw->srcimp_mgr_set_imapaddr(mgr->ctrl_blk, entry->addr); | ||
790 | hw->srcimp_mgr_commit_write(mgr->hw, mgr->ctrl_blk); | ||
791 | |||
792 | return 0; | ||
793 | } | ||
794 | |||
795 | static int srcimp_imap_add(struct srcimp_mgr *mgr, struct imapper *entry) | ||
796 | { | ||
797 | unsigned long flags; | ||
798 | int err; | ||
799 | |||
800 | spin_lock_irqsave(&mgr->imap_lock, flags); | ||
801 | if ((0 == entry->addr) && (mgr->init_imap_added)) { | ||
802 | input_mapper_delete(&mgr->imappers, | ||
803 | mgr->init_imap, srcimp_map_op, mgr); | ||
804 | mgr->init_imap_added = 0; | ||
805 | } | ||
806 | err = input_mapper_add(&mgr->imappers, entry, srcimp_map_op, mgr); | ||
807 | spin_unlock_irqrestore(&mgr->imap_lock, flags); | ||
808 | |||
809 | return err; | ||
810 | } | ||
811 | |||
812 | static int srcimp_imap_delete(struct srcimp_mgr *mgr, struct imapper *entry) | ||
813 | { | ||
814 | unsigned long flags; | ||
815 | int err; | ||
816 | |||
817 | spin_lock_irqsave(&mgr->imap_lock, flags); | ||
818 | err = input_mapper_delete(&mgr->imappers, entry, srcimp_map_op, mgr); | ||
819 | if (list_empty(&mgr->imappers)) { | ||
820 | input_mapper_add(&mgr->imappers, mgr->init_imap, | ||
821 | srcimp_map_op, mgr); | ||
822 | mgr->init_imap_added = 1; | ||
823 | } | ||
824 | spin_unlock_irqrestore(&mgr->imap_lock, flags); | ||
825 | |||
826 | return err; | ||
827 | } | ||
828 | |||
829 | int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrcimp_mgr) | ||
830 | { | ||
831 | int err; | ||
832 | struct srcimp_mgr *srcimp_mgr; | ||
833 | struct imapper *entry; | ||
834 | |||
835 | *rsrcimp_mgr = NULL; | ||
836 | srcimp_mgr = kzalloc(sizeof(*srcimp_mgr), GFP_KERNEL); | ||
837 | if (NULL == srcimp_mgr) | ||
838 | return -ENOMEM; | ||
839 | |||
840 | err = rsc_mgr_init(&srcimp_mgr->mgr, SRCIMP, SRCIMP_RESOURCE_NUM, hw); | ||
841 | if (err) | ||
842 | goto error1; | ||
843 | |||
844 | spin_lock_init(&srcimp_mgr->mgr_lock); | ||
845 | spin_lock_init(&srcimp_mgr->imap_lock); | ||
846 | INIT_LIST_HEAD(&srcimp_mgr->imappers); | ||
847 | entry = kzalloc(sizeof(*entry), GFP_KERNEL); | ||
848 | if (NULL == entry) { | ||
849 | err = -ENOMEM; | ||
850 | goto error2; | ||
851 | } | ||
852 | entry->slot = entry->addr = entry->next = entry->user = 0; | ||
853 | list_add(&entry->list, &srcimp_mgr->imappers); | ||
854 | srcimp_mgr->init_imap = entry; | ||
855 | srcimp_mgr->init_imap_added = 1; | ||
856 | |||
857 | srcimp_mgr->get_srcimp = get_srcimp_rsc; | ||
858 | srcimp_mgr->put_srcimp = put_srcimp_rsc; | ||
859 | srcimp_mgr->imap_add = srcimp_imap_add; | ||
860 | srcimp_mgr->imap_delete = srcimp_imap_delete; | ||
861 | |||
862 | *rsrcimp_mgr = srcimp_mgr; | ||
863 | |||
864 | return 0; | ||
865 | |||
866 | error2: | ||
867 | rsc_mgr_uninit(&srcimp_mgr->mgr); | ||
868 | error1: | ||
869 | kfree(srcimp_mgr); | ||
870 | return err; | ||
871 | } | ||
872 | |||
873 | int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr) | ||
874 | { | ||
875 | unsigned long flags; | ||
876 | |||
877 | /* free src input mapper list */ | ||
878 | spin_lock_irqsave(&srcimp_mgr->imap_lock, flags); | ||
879 | free_input_mapper_list(&srcimp_mgr->imappers); | ||
880 | spin_unlock_irqrestore(&srcimp_mgr->imap_lock, flags); | ||
881 | |||
882 | rsc_mgr_uninit(&srcimp_mgr->mgr); | ||
883 | kfree(srcimp_mgr); | ||
884 | |||
885 | return 0; | ||
886 | } | ||
diff --git a/sound/pci/ctxfi/ctsrc.h b/sound/pci/ctxfi/ctsrc.h new file mode 100644 index 000000000000..259366aabcac --- /dev/null +++ b/sound/pci/ctxfi/ctsrc.h | |||
@@ -0,0 +1,149 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctsrc.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of the Sample Rate Convertor | ||
12 | * resource management object. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date May 13 2008 | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | #ifndef CTSRC_H | ||
20 | #define CTSRC_H | ||
21 | |||
22 | #include "ctresource.h" | ||
23 | #include "ctimap.h" | ||
24 | #include <linux/spinlock.h> | ||
25 | #include <linux/list.h> | ||
26 | |||
27 | #define SRC_STATE_OFF 0x0 | ||
28 | #define SRC_STATE_INIT 0x4 | ||
29 | #define SRC_STATE_RUN 0x5 | ||
30 | |||
31 | #define SRC_SF_U8 0x0 | ||
32 | #define SRC_SF_S16 0x1 | ||
33 | #define SRC_SF_S24 0x2 | ||
34 | #define SRC_SF_S32 0x3 | ||
35 | #define SRC_SF_F32 0x4 | ||
36 | |||
37 | /* Define the descriptor of a src resource */ | ||
38 | enum SRCMODE { | ||
39 | MEMRD, /* Read data from host memory */ | ||
40 | MEMWR, /* Write data to host memory */ | ||
41 | ARCRW, /* Read from and write to audio ring channel */ | ||
42 | NUM_SRCMODES | ||
43 | }; | ||
44 | |||
45 | struct src_rsc_ops; | ||
46 | |||
47 | struct src { | ||
48 | struct rsc rsc; /* Basic resource info */ | ||
49 | struct src *intlv; /* Pointer to next interleaved SRC in a series */ | ||
50 | struct src_rsc_ops *ops; /* SRC specific operations */ | ||
51 | /* Number of contiguous srcs for interleaved usage */ | ||
52 | unsigned char multi; | ||
53 | unsigned char mode; /* Working mode of this SRC resource */ | ||
54 | }; | ||
55 | |||
56 | struct src_rsc_ops { | ||
57 | int (*set_state)(struct src *src, unsigned int state); | ||
58 | int (*set_bm)(struct src *src, unsigned int bm); | ||
59 | int (*set_sf)(struct src *src, unsigned int sf); | ||
60 | int (*set_pm)(struct src *src, unsigned int pm); | ||
61 | int (*set_rom)(struct src *src, unsigned int rom); | ||
62 | int (*set_vo)(struct src *src, unsigned int vo); | ||
63 | int (*set_st)(struct src *src, unsigned int st); | ||
64 | int (*set_bp)(struct src *src, unsigned int bp); | ||
65 | int (*set_cisz)(struct src *src, unsigned int cisz); | ||
66 | int (*set_ca)(struct src *src, unsigned int ca); | ||
67 | int (*set_sa)(struct src *src, unsigned int sa); | ||
68 | int (*set_la)(struct src *src, unsigned int la); | ||
69 | int (*set_pitch)(struct src *src, unsigned int pitch); | ||
70 | int (*set_clr_zbufs)(struct src *src); | ||
71 | int (*commit_write)(struct src *src); | ||
72 | int (*get_ca)(struct src *src); | ||
73 | int (*init)(struct src *src); | ||
74 | struct src* (*next_interleave)(struct src *src); | ||
75 | }; | ||
76 | |||
77 | /* Define src resource request description info */ | ||
78 | struct src_desc { | ||
79 | /* Number of contiguous master srcs for interleaved usage */ | ||
80 | unsigned char multi; | ||
81 | unsigned char msr; | ||
82 | unsigned char mode; /* Working mode of the requested srcs */ | ||
83 | }; | ||
84 | |||
85 | /* Define src manager object */ | ||
86 | struct src_mgr { | ||
87 | struct rsc_mgr mgr; /* Basic resource manager info */ | ||
88 | spinlock_t mgr_lock; | ||
89 | |||
90 | /* request src resource */ | ||
91 | int (*get_src)(struct src_mgr *mgr, | ||
92 | const struct src_desc *desc, struct src **rsrc); | ||
93 | /* return src resource */ | ||
94 | int (*put_src)(struct src_mgr *mgr, struct src *src); | ||
95 | int (*src_enable_s)(struct src_mgr *mgr, struct src *src); | ||
96 | int (*src_enable)(struct src_mgr *mgr, struct src *src); | ||
97 | int (*src_disable)(struct src_mgr *mgr, struct src *src); | ||
98 | int (*commit_write)(struct src_mgr *mgr); | ||
99 | }; | ||
100 | |||
101 | /* Define the descriptor of a SRC Input Mapper resource */ | ||
102 | struct srcimp_mgr; | ||
103 | struct srcimp_rsc_ops; | ||
104 | |||
105 | struct srcimp { | ||
106 | struct rsc rsc; | ||
107 | unsigned char idx[8]; | ||
108 | struct imapper *imappers; | ||
109 | unsigned int mapped; /* A bit-map indicating which conj rsc is mapped */ | ||
110 | struct srcimp_mgr *mgr; | ||
111 | struct srcimp_rsc_ops *ops; | ||
112 | }; | ||
113 | |||
114 | struct srcimp_rsc_ops { | ||
115 | int (*map)(struct srcimp *srcimp, struct src *user, struct rsc *input); | ||
116 | int (*unmap)(struct srcimp *srcimp); | ||
117 | }; | ||
118 | |||
119 | /* Define SRCIMP resource request description info */ | ||
120 | struct srcimp_desc { | ||
121 | unsigned int msr; | ||
122 | }; | ||
123 | |||
124 | struct srcimp_mgr { | ||
125 | struct rsc_mgr mgr; /* Basic resource manager info */ | ||
126 | spinlock_t mgr_lock; | ||
127 | spinlock_t imap_lock; | ||
128 | struct list_head imappers; | ||
129 | struct imapper *init_imap; | ||
130 | unsigned int init_imap_added; | ||
131 | |||
132 | /* request srcimp resource */ | ||
133 | int (*get_srcimp)(struct srcimp_mgr *mgr, | ||
134 | const struct srcimp_desc *desc, | ||
135 | struct srcimp **rsrcimp); | ||
136 | /* return srcimp resource */ | ||
137 | int (*put_srcimp)(struct srcimp_mgr *mgr, struct srcimp *srcimp); | ||
138 | int (*imap_add)(struct srcimp_mgr *mgr, struct imapper *entry); | ||
139 | int (*imap_delete)(struct srcimp_mgr *mgr, struct imapper *entry); | ||
140 | }; | ||
141 | |||
142 | /* Constructor and destructor of SRC resource manager */ | ||
143 | int src_mgr_create(void *hw, struct src_mgr **rsrc_mgr); | ||
144 | int src_mgr_destroy(struct src_mgr *src_mgr); | ||
145 | /* Constructor and destructor of SRCIMP resource manager */ | ||
146 | int srcimp_mgr_create(void *hw, struct srcimp_mgr **rsrc_mgr); | ||
147 | int srcimp_mgr_destroy(struct srcimp_mgr *srcimp_mgr); | ||
148 | |||
149 | #endif /* CTSRC_H */ | ||
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c new file mode 100644 index 000000000000..779c6c3591a5 --- /dev/null +++ b/sound/pci/ctxfi/cttimer.c | |||
@@ -0,0 +1,441 @@ | |||
1 | /* | ||
2 | * PCM timer handling on ctxfi | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | */ | ||
8 | |||
9 | #include <linux/slab.h> | ||
10 | #include <linux/math64.h> | ||
11 | #include <linux/moduleparam.h> | ||
12 | #include <sound/core.h> | ||
13 | #include <sound/pcm.h> | ||
14 | #include "ctatc.h" | ||
15 | #include "cthardware.h" | ||
16 | #include "cttimer.h" | ||
17 | |||
18 | static int use_system_timer; | ||
19 | MODULE_PARM_DESC(use_system_timer, "Foce to use system-timer"); | ||
20 | module_param(use_system_timer, bool, S_IRUGO); | ||
21 | |||
22 | struct ct_timer_ops { | ||
23 | void (*init)(struct ct_timer_instance *); | ||
24 | void (*prepare)(struct ct_timer_instance *); | ||
25 | void (*start)(struct ct_timer_instance *); | ||
26 | void (*stop)(struct ct_timer_instance *); | ||
27 | void (*free_instance)(struct ct_timer_instance *); | ||
28 | void (*interrupt)(struct ct_timer *); | ||
29 | void (*free_global)(struct ct_timer *); | ||
30 | }; | ||
31 | |||
32 | /* timer instance -- assigned to each PCM stream */ | ||
33 | struct ct_timer_instance { | ||
34 | spinlock_t lock; | ||
35 | struct ct_timer *timer_base; | ||
36 | struct ct_atc_pcm *apcm; | ||
37 | struct snd_pcm_substream *substream; | ||
38 | struct timer_list timer; | ||
39 | struct list_head instance_list; | ||
40 | struct list_head running_list; | ||
41 | unsigned int position; | ||
42 | unsigned int frag_count; | ||
43 | unsigned int running:1; | ||
44 | unsigned int need_update:1; | ||
45 | }; | ||
46 | |||
47 | /* timer instance manager */ | ||
48 | struct ct_timer { | ||
49 | spinlock_t lock; /* global timer lock (for xfitimer) */ | ||
50 | spinlock_t list_lock; /* lock for instance list */ | ||
51 | struct ct_atc *atc; | ||
52 | struct ct_timer_ops *ops; | ||
53 | struct list_head instance_head; | ||
54 | struct list_head running_head; | ||
55 | unsigned int wc; /* current wallclock */ | ||
56 | unsigned int irq_handling:1; /* in IRQ handling */ | ||
57 | unsigned int reprogram:1; /* need to reprogram the internval */ | ||
58 | unsigned int running:1; /* global timer running */ | ||
59 | }; | ||
60 | |||
61 | |||
62 | /* | ||
63 | * system-timer-based updates | ||
64 | */ | ||
65 | |||
66 | static void ct_systimer_callback(unsigned long data) | ||
67 | { | ||
68 | struct ct_timer_instance *ti = (struct ct_timer_instance *)data; | ||
69 | struct snd_pcm_substream *substream = ti->substream; | ||
70 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
71 | struct ct_atc_pcm *apcm = ti->apcm; | ||
72 | unsigned int period_size = runtime->period_size; | ||
73 | unsigned int buffer_size = runtime->buffer_size; | ||
74 | unsigned long flags; | ||
75 | unsigned int position, dist, interval; | ||
76 | |||
77 | position = substream->ops->pointer(substream); | ||
78 | dist = (position + buffer_size - ti->position) % buffer_size; | ||
79 | if (dist >= period_size || | ||
80 | position / period_size != ti->position / period_size) { | ||
81 | apcm->interrupt(apcm); | ||
82 | ti->position = position; | ||
83 | } | ||
84 | /* Add extra HZ*5/1000 to avoid overrun issue when recording | ||
85 | * at 8kHz in 8-bit format or at 88kHz in 24-bit format. */ | ||
86 | interval = ((period_size - (position % period_size)) | ||
87 | * HZ + (runtime->rate - 1)) / runtime->rate + HZ * 5 / 1000; | ||
88 | spin_lock_irqsave(&ti->lock, flags); | ||
89 | if (ti->running) | ||
90 | mod_timer(&ti->timer, jiffies + interval); | ||
91 | spin_unlock_irqrestore(&ti->lock, flags); | ||
92 | } | ||
93 | |||
94 | static void ct_systimer_init(struct ct_timer_instance *ti) | ||
95 | { | ||
96 | setup_timer(&ti->timer, ct_systimer_callback, | ||
97 | (unsigned long)ti); | ||
98 | } | ||
99 | |||
100 | static void ct_systimer_start(struct ct_timer_instance *ti) | ||
101 | { | ||
102 | struct snd_pcm_runtime *runtime = ti->substream->runtime; | ||
103 | unsigned long flags; | ||
104 | |||
105 | spin_lock_irqsave(&ti->lock, flags); | ||
106 | ti->running = 1; | ||
107 | mod_timer(&ti->timer, | ||
108 | jiffies + (runtime->period_size * HZ + | ||
109 | (runtime->rate - 1)) / runtime->rate); | ||
110 | spin_unlock_irqrestore(&ti->lock, flags); | ||
111 | } | ||
112 | |||
113 | static void ct_systimer_stop(struct ct_timer_instance *ti) | ||
114 | { | ||
115 | unsigned long flags; | ||
116 | |||
117 | spin_lock_irqsave(&ti->lock, flags); | ||
118 | ti->running = 0; | ||
119 | del_timer(&ti->timer); | ||
120 | spin_unlock_irqrestore(&ti->lock, flags); | ||
121 | } | ||
122 | |||
123 | static void ct_systimer_prepare(struct ct_timer_instance *ti) | ||
124 | { | ||
125 | ct_systimer_stop(ti); | ||
126 | try_to_del_timer_sync(&ti->timer); | ||
127 | } | ||
128 | |||
129 | #define ct_systimer_free ct_systimer_prepare | ||
130 | |||
131 | static struct ct_timer_ops ct_systimer_ops = { | ||
132 | .init = ct_systimer_init, | ||
133 | .free_instance = ct_systimer_free, | ||
134 | .prepare = ct_systimer_prepare, | ||
135 | .start = ct_systimer_start, | ||
136 | .stop = ct_systimer_stop, | ||
137 | }; | ||
138 | |||
139 | |||
140 | /* | ||
141 | * Handling multiple streams using a global emu20k1 timer irq | ||
142 | */ | ||
143 | |||
144 | #define CT_TIMER_FREQ 48000 | ||
145 | #define MIN_TICKS 1 | ||
146 | #define MAX_TICKS ((1 << 13) - 1) | ||
147 | |||
148 | static void ct_xfitimer_irq_rearm(struct ct_timer *atimer, int ticks) | ||
149 | { | ||
150 | struct hw *hw = atimer->atc->hw; | ||
151 | if (ticks > MAX_TICKS) | ||
152 | ticks = MAX_TICKS; | ||
153 | hw->set_timer_tick(hw, ticks); | ||
154 | if (!atimer->running) | ||
155 | hw->set_timer_irq(hw, 1); | ||
156 | atimer->running = 1; | ||
157 | } | ||
158 | |||
159 | static void ct_xfitimer_irq_stop(struct ct_timer *atimer) | ||
160 | { | ||
161 | if (atimer->running) { | ||
162 | struct hw *hw = atimer->atc->hw; | ||
163 | hw->set_timer_irq(hw, 0); | ||
164 | hw->set_timer_tick(hw, 0); | ||
165 | atimer->running = 0; | ||
166 | } | ||
167 | } | ||
168 | |||
169 | static inline unsigned int ct_xfitimer_get_wc(struct ct_timer *atimer) | ||
170 | { | ||
171 | struct hw *hw = atimer->atc->hw; | ||
172 | return hw->get_wc(hw); | ||
173 | } | ||
174 | |||
175 | /* | ||
176 | * reprogram the timer interval; | ||
177 | * checks the running instance list and determines the next timer interval. | ||
178 | * also updates the each stream position, returns the number of streams | ||
179 | * to call snd_pcm_period_elapsed() appropriately | ||
180 | * | ||
181 | * call this inside the lock and irq disabled | ||
182 | */ | ||
183 | static int ct_xfitimer_reprogram(struct ct_timer *atimer) | ||
184 | { | ||
185 | struct ct_timer_instance *ti; | ||
186 | unsigned int min_intr = (unsigned int)-1; | ||
187 | int updates = 0; | ||
188 | unsigned int wc, diff; | ||
189 | |||
190 | if (list_empty(&atimer->running_head)) { | ||
191 | ct_xfitimer_irq_stop(atimer); | ||
192 | atimer->reprogram = 0; /* clear flag */ | ||
193 | return 0; | ||
194 | } | ||
195 | |||
196 | wc = ct_xfitimer_get_wc(atimer); | ||
197 | diff = wc - atimer->wc; | ||
198 | atimer->wc = wc; | ||
199 | list_for_each_entry(ti, &atimer->running_head, running_list) { | ||
200 | if (ti->frag_count > diff) | ||
201 | ti->frag_count -= diff; | ||
202 | else { | ||
203 | unsigned int pos; | ||
204 | unsigned int period_size, rate; | ||
205 | |||
206 | period_size = ti->substream->runtime->period_size; | ||
207 | rate = ti->substream->runtime->rate; | ||
208 | pos = ti->substream->ops->pointer(ti->substream); | ||
209 | if (pos / period_size != ti->position / period_size) { | ||
210 | ti->need_update = 1; | ||
211 | ti->position = pos; | ||
212 | updates++; | ||
213 | } | ||
214 | pos %= period_size; | ||
215 | pos = period_size - pos; | ||
216 | ti->frag_count = div_u64((u64)pos * CT_TIMER_FREQ + | ||
217 | rate - 1, rate); | ||
218 | } | ||
219 | if (ti->frag_count < min_intr) | ||
220 | min_intr = ti->frag_count; | ||
221 | } | ||
222 | |||
223 | if (min_intr < MIN_TICKS) | ||
224 | min_intr = MIN_TICKS; | ||
225 | ct_xfitimer_irq_rearm(atimer, min_intr); | ||
226 | atimer->reprogram = 0; /* clear flag */ | ||
227 | return updates; | ||
228 | } | ||
229 | |||
230 | /* look through the instance list and call period_elapsed if needed */ | ||
231 | static void ct_xfitimer_check_period(struct ct_timer *atimer) | ||
232 | { | ||
233 | struct ct_timer_instance *ti; | ||
234 | unsigned long flags; | ||
235 | |||
236 | spin_lock_irqsave(&atimer->list_lock, flags); | ||
237 | list_for_each_entry(ti, &atimer->instance_head, instance_list) { | ||
238 | if (ti->need_update) { | ||
239 | ti->need_update = 0; | ||
240 | ti->apcm->interrupt(ti->apcm); | ||
241 | } | ||
242 | } | ||
243 | spin_unlock_irqrestore(&atimer->list_lock, flags); | ||
244 | } | ||
245 | |||
246 | /* Handle timer-interrupt */ | ||
247 | static void ct_xfitimer_callback(struct ct_timer *atimer) | ||
248 | { | ||
249 | int update; | ||
250 | unsigned long flags; | ||
251 | |||
252 | spin_lock_irqsave(&atimer->lock, flags); | ||
253 | atimer->irq_handling = 1; | ||
254 | do { | ||
255 | update = ct_xfitimer_reprogram(atimer); | ||
256 | spin_unlock(&atimer->lock); | ||
257 | if (update) | ||
258 | ct_xfitimer_check_period(atimer); | ||
259 | spin_lock(&atimer->lock); | ||
260 | } while (atimer->reprogram); | ||
261 | atimer->irq_handling = 0; | ||
262 | spin_unlock_irqrestore(&atimer->lock, flags); | ||
263 | } | ||
264 | |||
265 | static void ct_xfitimer_prepare(struct ct_timer_instance *ti) | ||
266 | { | ||
267 | ti->frag_count = ti->substream->runtime->period_size; | ||
268 | ti->need_update = 0; | ||
269 | } | ||
270 | |||
271 | |||
272 | /* start/stop the timer */ | ||
273 | static void ct_xfitimer_update(struct ct_timer *atimer) | ||
274 | { | ||
275 | unsigned long flags; | ||
276 | int update; | ||
277 | |||
278 | spin_lock_irqsave(&atimer->lock, flags); | ||
279 | if (atimer->irq_handling) { | ||
280 | /* reached from IRQ handler; let it handle later */ | ||
281 | atimer->reprogram = 1; | ||
282 | spin_unlock_irqrestore(&atimer->lock, flags); | ||
283 | return; | ||
284 | } | ||
285 | |||
286 | ct_xfitimer_irq_stop(atimer); | ||
287 | update = ct_xfitimer_reprogram(atimer); | ||
288 | spin_unlock_irqrestore(&atimer->lock, flags); | ||
289 | if (update) | ||
290 | ct_xfitimer_check_period(atimer); | ||
291 | } | ||
292 | |||
293 | static void ct_xfitimer_start(struct ct_timer_instance *ti) | ||
294 | { | ||
295 | struct ct_timer *atimer = ti->timer_base; | ||
296 | unsigned long flags; | ||
297 | |||
298 | spin_lock_irqsave(&atimer->lock, flags); | ||
299 | if (list_empty(&ti->running_list)) | ||
300 | atimer->wc = ct_xfitimer_get_wc(atimer); | ||
301 | list_add(&ti->running_list, &atimer->running_head); | ||
302 | spin_unlock_irqrestore(&atimer->lock, flags); | ||
303 | ct_xfitimer_update(atimer); | ||
304 | } | ||
305 | |||
306 | static void ct_xfitimer_stop(struct ct_timer_instance *ti) | ||
307 | { | ||
308 | struct ct_timer *atimer = ti->timer_base; | ||
309 | unsigned long flags; | ||
310 | |||
311 | spin_lock_irqsave(&atimer->lock, flags); | ||
312 | list_del_init(&ti->running_list); | ||
313 | ti->need_update = 0; | ||
314 | spin_unlock_irqrestore(&atimer->lock, flags); | ||
315 | ct_xfitimer_update(atimer); | ||
316 | } | ||
317 | |||
318 | static void ct_xfitimer_free_global(struct ct_timer *atimer) | ||
319 | { | ||
320 | ct_xfitimer_irq_stop(atimer); | ||
321 | } | ||
322 | |||
323 | static struct ct_timer_ops ct_xfitimer_ops = { | ||
324 | .prepare = ct_xfitimer_prepare, | ||
325 | .start = ct_xfitimer_start, | ||
326 | .stop = ct_xfitimer_stop, | ||
327 | .interrupt = ct_xfitimer_callback, | ||
328 | .free_global = ct_xfitimer_free_global, | ||
329 | }; | ||
330 | |||
331 | /* | ||
332 | * timer instance | ||
333 | */ | ||
334 | |||
335 | struct ct_timer_instance * | ||
336 | ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm) | ||
337 | { | ||
338 | struct ct_timer_instance *ti; | ||
339 | |||
340 | ti = kzalloc(sizeof(*ti), GFP_KERNEL); | ||
341 | if (!ti) | ||
342 | return NULL; | ||
343 | spin_lock_init(&ti->lock); | ||
344 | INIT_LIST_HEAD(&ti->instance_list); | ||
345 | INIT_LIST_HEAD(&ti->running_list); | ||
346 | ti->timer_base = atimer; | ||
347 | ti->apcm = apcm; | ||
348 | ti->substream = apcm->substream; | ||
349 | if (atimer->ops->init) | ||
350 | atimer->ops->init(ti); | ||
351 | |||
352 | spin_lock_irq(&atimer->list_lock); | ||
353 | list_add(&ti->instance_list, &atimer->instance_head); | ||
354 | spin_unlock_irq(&atimer->list_lock); | ||
355 | |||
356 | return ti; | ||
357 | } | ||
358 | |||
359 | void ct_timer_prepare(struct ct_timer_instance *ti) | ||
360 | { | ||
361 | if (ti->timer_base->ops->prepare) | ||
362 | ti->timer_base->ops->prepare(ti); | ||
363 | ti->position = 0; | ||
364 | ti->running = 0; | ||
365 | } | ||
366 | |||
367 | void ct_timer_start(struct ct_timer_instance *ti) | ||
368 | { | ||
369 | struct ct_timer *atimer = ti->timer_base; | ||
370 | atimer->ops->start(ti); | ||
371 | } | ||
372 | |||
373 | void ct_timer_stop(struct ct_timer_instance *ti) | ||
374 | { | ||
375 | struct ct_timer *atimer = ti->timer_base; | ||
376 | atimer->ops->stop(ti); | ||
377 | } | ||
378 | |||
379 | void ct_timer_instance_free(struct ct_timer_instance *ti) | ||
380 | { | ||
381 | struct ct_timer *atimer = ti->timer_base; | ||
382 | |||
383 | atimer->ops->stop(ti); /* to be sure */ | ||
384 | if (atimer->ops->free_instance) | ||
385 | atimer->ops->free_instance(ti); | ||
386 | |||
387 | spin_lock_irq(&atimer->list_lock); | ||
388 | list_del(&ti->instance_list); | ||
389 | spin_unlock_irq(&atimer->list_lock); | ||
390 | |||
391 | kfree(ti); | ||
392 | } | ||
393 | |||
394 | /* | ||
395 | * timer manager | ||
396 | */ | ||
397 | |||
398 | static void ct_timer_interrupt(void *data, unsigned int status) | ||
399 | { | ||
400 | struct ct_timer *timer = data; | ||
401 | |||
402 | /* Interval timer interrupt */ | ||
403 | if ((status & IT_INT) && timer->ops->interrupt) | ||
404 | timer->ops->interrupt(timer); | ||
405 | } | ||
406 | |||
407 | struct ct_timer *ct_timer_new(struct ct_atc *atc) | ||
408 | { | ||
409 | struct ct_timer *atimer; | ||
410 | struct hw *hw; | ||
411 | |||
412 | atimer = kzalloc(sizeof(*atimer), GFP_KERNEL); | ||
413 | if (!atimer) | ||
414 | return NULL; | ||
415 | spin_lock_init(&atimer->lock); | ||
416 | spin_lock_init(&atimer->list_lock); | ||
417 | INIT_LIST_HEAD(&atimer->instance_head); | ||
418 | INIT_LIST_HEAD(&atimer->running_head); | ||
419 | atimer->atc = atc; | ||
420 | hw = atc->hw; | ||
421 | if (!use_system_timer && hw->set_timer_irq) { | ||
422 | snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n"); | ||
423 | atimer->ops = &ct_xfitimer_ops; | ||
424 | hw->irq_callback_data = atimer; | ||
425 | hw->irq_callback = ct_timer_interrupt; | ||
426 | } else { | ||
427 | snd_printd(KERN_INFO "ctxfi: Use system timer\n"); | ||
428 | atimer->ops = &ct_systimer_ops; | ||
429 | } | ||
430 | return atimer; | ||
431 | } | ||
432 | |||
433 | void ct_timer_free(struct ct_timer *atimer) | ||
434 | { | ||
435 | struct hw *hw = atimer->atc->hw; | ||
436 | hw->irq_callback = NULL; | ||
437 | if (atimer->ops->free_global) | ||
438 | atimer->ops->free_global(atimer); | ||
439 | kfree(atimer); | ||
440 | } | ||
441 | |||
diff --git a/sound/pci/ctxfi/cttimer.h b/sound/pci/ctxfi/cttimer.h new file mode 100644 index 000000000000..979348229291 --- /dev/null +++ b/sound/pci/ctxfi/cttimer.h | |||
@@ -0,0 +1,29 @@ | |||
1 | /* | ||
2 | * Timer handling | ||
3 | */ | ||
4 | |||
5 | #ifndef __CTTIMER_H | ||
6 | #define __CTTIMER_H | ||
7 | |||
8 | #include <linux/spinlock.h> | ||
9 | #include <linux/timer.h> | ||
10 | #include <linux/list.h> | ||
11 | |||
12 | struct snd_pcm_substream; | ||
13 | struct ct_atc; | ||
14 | struct ct_atc_pcm; | ||
15 | |||
16 | struct ct_timer; | ||
17 | struct ct_timer_instance; | ||
18 | |||
19 | struct ct_timer *ct_timer_new(struct ct_atc *atc); | ||
20 | void ct_timer_free(struct ct_timer *atimer); | ||
21 | |||
22 | struct ct_timer_instance * | ||
23 | ct_timer_instance_new(struct ct_timer *atimer, struct ct_atc_pcm *apcm); | ||
24 | void ct_timer_instance_free(struct ct_timer_instance *ti); | ||
25 | void ct_timer_start(struct ct_timer_instance *ti); | ||
26 | void ct_timer_stop(struct ct_timer_instance *ti); | ||
27 | void ct_timer_prepare(struct ct_timer_instance *ti); | ||
28 | |||
29 | #endif /* __CTTIMER_H */ | ||
diff --git a/sound/pci/ctxfi/ctvmem.c b/sound/pci/ctxfi/ctvmem.c new file mode 100644 index 000000000000..67665a7e43c6 --- /dev/null +++ b/sound/pci/ctxfi/ctvmem.c | |||
@@ -0,0 +1,250 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctvmem.c | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the implementation of virtual memory management object | ||
12 | * for card device. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date Apr 1 2008 | ||
16 | */ | ||
17 | |||
18 | #include "ctvmem.h" | ||
19 | #include <linux/slab.h> | ||
20 | #include <linux/mm.h> | ||
21 | #include <linux/io.h> | ||
22 | #include <sound/pcm.h> | ||
23 | |||
24 | #define CT_PTES_PER_PAGE (CT_PAGE_SIZE / sizeof(void *)) | ||
25 | #define CT_ADDRS_PER_PAGE (CT_PTES_PER_PAGE * CT_PAGE_SIZE) | ||
26 | |||
27 | /* * | ||
28 | * Find or create vm block based on requested @size. | ||
29 | * @size must be page aligned. | ||
30 | * */ | ||
31 | static struct ct_vm_block * | ||
32 | get_vm_block(struct ct_vm *vm, unsigned int size) | ||
33 | { | ||
34 | struct ct_vm_block *block = NULL, *entry; | ||
35 | struct list_head *pos; | ||
36 | |||
37 | size = CT_PAGE_ALIGN(size); | ||
38 | if (size > vm->size) { | ||
39 | printk(KERN_ERR "ctxfi: Fail! No sufficient device virtural " | ||
40 | "memory space available!\n"); | ||
41 | return NULL; | ||
42 | } | ||
43 | |||
44 | mutex_lock(&vm->lock); | ||
45 | list_for_each(pos, &vm->unused) { | ||
46 | entry = list_entry(pos, struct ct_vm_block, list); | ||
47 | if (entry->size >= size) | ||
48 | break; /* found a block that is big enough */ | ||
49 | } | ||
50 | if (pos == &vm->unused) | ||
51 | goto out; | ||
52 | |||
53 | if (entry->size == size) { | ||
54 | /* Move the vm node from unused list to used list directly */ | ||
55 | list_del(&entry->list); | ||
56 | list_add(&entry->list, &vm->used); | ||
57 | vm->size -= size; | ||
58 | block = entry; | ||
59 | goto out; | ||
60 | } | ||
61 | |||
62 | block = kzalloc(sizeof(*block), GFP_KERNEL); | ||
63 | if (NULL == block) | ||
64 | goto out; | ||
65 | |||
66 | block->addr = entry->addr; | ||
67 | block->size = size; | ||
68 | list_add(&block->list, &vm->used); | ||
69 | entry->addr += size; | ||
70 | entry->size -= size; | ||
71 | vm->size -= size; | ||
72 | |||
73 | out: | ||
74 | mutex_unlock(&vm->lock); | ||
75 | return block; | ||
76 | } | ||
77 | |||
78 | static void put_vm_block(struct ct_vm *vm, struct ct_vm_block *block) | ||
79 | { | ||
80 | struct ct_vm_block *entry, *pre_ent; | ||
81 | struct list_head *pos, *pre; | ||
82 | |||
83 | block->size = CT_PAGE_ALIGN(block->size); | ||
84 | |||
85 | mutex_lock(&vm->lock); | ||
86 | list_del(&block->list); | ||
87 | vm->size += block->size; | ||
88 | |||
89 | list_for_each(pos, &vm->unused) { | ||
90 | entry = list_entry(pos, struct ct_vm_block, list); | ||
91 | if (entry->addr >= (block->addr + block->size)) | ||
92 | break; /* found a position */ | ||
93 | } | ||
94 | if (pos == &vm->unused) { | ||
95 | list_add_tail(&block->list, &vm->unused); | ||
96 | entry = block; | ||
97 | } else { | ||
98 | if ((block->addr + block->size) == entry->addr) { | ||
99 | entry->addr = block->addr; | ||
100 | entry->size += block->size; | ||
101 | kfree(block); | ||
102 | } else { | ||
103 | __list_add(&block->list, pos->prev, pos); | ||
104 | entry = block; | ||
105 | } | ||
106 | } | ||
107 | |||
108 | pos = &entry->list; | ||
109 | pre = pos->prev; | ||
110 | while (pre != &vm->unused) { | ||
111 | entry = list_entry(pos, struct ct_vm_block, list); | ||
112 | pre_ent = list_entry(pre, struct ct_vm_block, list); | ||
113 | if ((pre_ent->addr + pre_ent->size) > entry->addr) | ||
114 | break; | ||
115 | |||
116 | pre_ent->size += entry->size; | ||
117 | list_del(pos); | ||
118 | kfree(entry); | ||
119 | pos = pre; | ||
120 | pre = pos->prev; | ||
121 | } | ||
122 | mutex_unlock(&vm->lock); | ||
123 | } | ||
124 | |||
125 | /* Map host addr (kmalloced/vmalloced) to device logical addr. */ | ||
126 | static struct ct_vm_block * | ||
127 | ct_vm_map(struct ct_vm *vm, struct snd_pcm_substream *substream, int size) | ||
128 | { | ||
129 | struct ct_vm_block *block; | ||
130 | unsigned int pte_start; | ||
131 | unsigned i, pages; | ||
132 | unsigned long *ptp; | ||
133 | |||
134 | block = get_vm_block(vm, size); | ||
135 | if (block == NULL) { | ||
136 | printk(KERN_ERR "ctxfi: No virtual memory block that is big " | ||
137 | "enough to allocate!\n"); | ||
138 | return NULL; | ||
139 | } | ||
140 | |||
141 | ptp = vm->ptp[0]; | ||
142 | pte_start = (block->addr >> CT_PAGE_SHIFT); | ||
143 | pages = block->size >> CT_PAGE_SHIFT; | ||
144 | for (i = 0; i < pages; i++) { | ||
145 | unsigned long addr; | ||
146 | addr = snd_pcm_sgbuf_get_addr(substream, i << CT_PAGE_SHIFT); | ||
147 | ptp[pte_start + i] = addr; | ||
148 | } | ||
149 | |||
150 | block->size = size; | ||
151 | return block; | ||
152 | } | ||
153 | |||
154 | static void ct_vm_unmap(struct ct_vm *vm, struct ct_vm_block *block) | ||
155 | { | ||
156 | /* do unmapping */ | ||
157 | put_vm_block(vm, block); | ||
158 | } | ||
159 | |||
160 | /* * | ||
161 | * return the host (kmalloced) addr of the @index-th device | ||
162 | * page talbe page on success, or NULL on failure. | ||
163 | * The first returned NULL indicates the termination. | ||
164 | * */ | ||
165 | static void * | ||
166 | ct_get_ptp_virt(struct ct_vm *vm, int index) | ||
167 | { | ||
168 | void *addr; | ||
169 | |||
170 | addr = (index >= CT_PTP_NUM) ? NULL : vm->ptp[index]; | ||
171 | |||
172 | return addr; | ||
173 | } | ||
174 | |||
175 | int ct_vm_create(struct ct_vm **rvm) | ||
176 | { | ||
177 | struct ct_vm *vm; | ||
178 | struct ct_vm_block *block; | ||
179 | int i; | ||
180 | |||
181 | *rvm = NULL; | ||
182 | |||
183 | vm = kzalloc(sizeof(*vm), GFP_KERNEL); | ||
184 | if (NULL == vm) | ||
185 | return -ENOMEM; | ||
186 | |||
187 | mutex_init(&vm->lock); | ||
188 | |||
189 | /* Allocate page table pages */ | ||
190 | for (i = 0; i < CT_PTP_NUM; i++) { | ||
191 | vm->ptp[i] = kmalloc(PAGE_SIZE, GFP_KERNEL); | ||
192 | if (NULL == vm->ptp[i]) | ||
193 | break; | ||
194 | } | ||
195 | if (!i) { | ||
196 | /* no page table pages are allocated */ | ||
197 | kfree(vm); | ||
198 | return -ENOMEM; | ||
199 | } | ||
200 | vm->size = CT_ADDRS_PER_PAGE * i; | ||
201 | /* Initialise remaining ptps */ | ||
202 | for (; i < CT_PTP_NUM; i++) | ||
203 | vm->ptp[i] = NULL; | ||
204 | |||
205 | vm->map = ct_vm_map; | ||
206 | vm->unmap = ct_vm_unmap; | ||
207 | vm->get_ptp_virt = ct_get_ptp_virt; | ||
208 | INIT_LIST_HEAD(&vm->unused); | ||
209 | INIT_LIST_HEAD(&vm->used); | ||
210 | block = kzalloc(sizeof(*block), GFP_KERNEL); | ||
211 | if (NULL != block) { | ||
212 | block->addr = 0; | ||
213 | block->size = vm->size; | ||
214 | list_add(&block->list, &vm->unused); | ||
215 | } | ||
216 | |||
217 | *rvm = vm; | ||
218 | return 0; | ||
219 | } | ||
220 | |||
221 | /* The caller must ensure no mapping pages are being used | ||
222 | * by hardware before calling this function */ | ||
223 | void ct_vm_destroy(struct ct_vm *vm) | ||
224 | { | ||
225 | int i; | ||
226 | struct list_head *pos; | ||
227 | struct ct_vm_block *entry; | ||
228 | |||
229 | /* free used and unused list nodes */ | ||
230 | while (!list_empty(&vm->used)) { | ||
231 | pos = vm->used.next; | ||
232 | list_del(pos); | ||
233 | entry = list_entry(pos, struct ct_vm_block, list); | ||
234 | kfree(entry); | ||
235 | } | ||
236 | while (!list_empty(&vm->unused)) { | ||
237 | pos = vm->unused.next; | ||
238 | list_del(pos); | ||
239 | entry = list_entry(pos, struct ct_vm_block, list); | ||
240 | kfree(entry); | ||
241 | } | ||
242 | |||
243 | /* free allocated page table pages */ | ||
244 | for (i = 0; i < CT_PTP_NUM; i++) | ||
245 | kfree(vm->ptp[i]); | ||
246 | |||
247 | vm->size = 0; | ||
248 | |||
249 | kfree(vm); | ||
250 | } | ||
diff --git a/sound/pci/ctxfi/ctvmem.h b/sound/pci/ctxfi/ctvmem.h new file mode 100644 index 000000000000..01e4fd0386a3 --- /dev/null +++ b/sound/pci/ctxfi/ctvmem.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /** | ||
2 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
3 | * | ||
4 | * This source file is released under GPL v2 license (no other versions). | ||
5 | * See the COPYING file included in the main directory of this source | ||
6 | * distribution for the license terms and conditions. | ||
7 | * | ||
8 | * @File ctvmem.h | ||
9 | * | ||
10 | * @Brief | ||
11 | * This file contains the definition of virtual memory management object | ||
12 | * for card device. | ||
13 | * | ||
14 | * @Author Liu Chun | ||
15 | * @Date Mar 28 2008 | ||
16 | */ | ||
17 | |||
18 | #ifndef CTVMEM_H | ||
19 | #define CTVMEM_H | ||
20 | |||
21 | #define CT_PTP_NUM 1 /* num of device page table pages */ | ||
22 | |||
23 | #include <linux/mutex.h> | ||
24 | #include <linux/list.h> | ||
25 | |||
26 | /* The chip can handle the page table of 4k pages | ||
27 | * (emu20k1 can handle even 8k pages, but we don't use it right now) | ||
28 | */ | ||
29 | #define CT_PAGE_SIZE 4096 | ||
30 | #define CT_PAGE_SHIFT 12 | ||
31 | #define CT_PAGE_MASK (~(PAGE_SIZE - 1)) | ||
32 | #define CT_PAGE_ALIGN(addr) ALIGN(addr, CT_PAGE_SIZE) | ||
33 | |||
34 | struct ct_vm_block { | ||
35 | unsigned int addr; /* starting logical addr of this block */ | ||
36 | unsigned int size; /* size of this device virtual mem block */ | ||
37 | struct list_head list; | ||
38 | }; | ||
39 | |||
40 | struct snd_pcm_substream; | ||
41 | |||
42 | /* Virtual memory management object for card device */ | ||
43 | struct ct_vm { | ||
44 | void *ptp[CT_PTP_NUM]; /* Device page table pages */ | ||
45 | unsigned int size; /* Available addr space in bytes */ | ||
46 | struct list_head unused; /* List of unused blocks */ | ||
47 | struct list_head used; /* List of used blocks */ | ||
48 | struct mutex lock; | ||
49 | |||
50 | /* Map host addr (kmalloced/vmalloced) to device logical addr. */ | ||
51 | struct ct_vm_block *(*map)(struct ct_vm *, struct snd_pcm_substream *, | ||
52 | int size); | ||
53 | /* Unmap device logical addr area. */ | ||
54 | void (*unmap)(struct ct_vm *, struct ct_vm_block *block); | ||
55 | void *(*get_ptp_virt)(struct ct_vm *vm, int index); | ||
56 | }; | ||
57 | |||
58 | int ct_vm_create(struct ct_vm **rvm); | ||
59 | void ct_vm_destroy(struct ct_vm *vm); | ||
60 | |||
61 | #endif /* CTVMEM_H */ | ||
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c new file mode 100644 index 000000000000..2d3dd89af151 --- /dev/null +++ b/sound/pci/ctxfi/xfi.c | |||
@@ -0,0 +1,142 @@ | |||
1 | /* | ||
2 | * xfi linux driver. | ||
3 | * | ||
4 | * Copyright (C) 2008, Creative Technology Ltd. All Rights Reserved. | ||
5 | * | ||
6 | * This source file is released under GPL v2 license (no other versions). | ||
7 | * See the COPYING file included in the main directory of this source | ||
8 | * distribution for the license terms and conditions. | ||
9 | */ | ||
10 | |||
11 | #include <linux/init.h> | ||
12 | #include <linux/pci.h> | ||
13 | #include <linux/moduleparam.h> | ||
14 | #include <linux/pci_ids.h> | ||
15 | #include <sound/core.h> | ||
16 | #include <sound/initval.h> | ||
17 | #include "ctatc.h" | ||
18 | #include "cthardware.h" | ||
19 | |||
20 | MODULE_AUTHOR("Creative Technology Ltd"); | ||
21 | MODULE_DESCRIPTION("X-Fi driver version 1.03"); | ||
22 | MODULE_LICENSE("GPL v2"); | ||
23 | MODULE_SUPPORTED_DEVICE("{{Creative Labs, Sound Blaster X-Fi}"); | ||
24 | |||
25 | static unsigned int reference_rate = 48000; | ||
26 | static unsigned int multiple = 2; | ||
27 | MODULE_PARM_DESC(reference_rate, "Reference rate (default=48000)"); | ||
28 | module_param(reference_rate, uint, S_IRUGO); | ||
29 | MODULE_PARM_DESC(multiple, "Rate multiplier (default=2)"); | ||
30 | module_param(multiple, uint, S_IRUGO); | ||
31 | |||
32 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
33 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
34 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
35 | |||
36 | module_param_array(index, int, NULL, 0444); | ||
37 | MODULE_PARM_DESC(index, "Index value for Creative X-Fi driver"); | ||
38 | module_param_array(id, charp, NULL, 0444); | ||
39 | MODULE_PARM_DESC(id, "ID string for Creative X-Fi driver"); | ||
40 | module_param_array(enable, bool, NULL, 0444); | ||
41 | MODULE_PARM_DESC(enable, "Enable Creative X-Fi driver"); | ||
42 | |||
43 | static struct pci_device_id ct_pci_dev_ids[] = { | ||
44 | /* only X-Fi is supported, so... */ | ||
45 | { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K1), | ||
46 | .driver_data = ATC20K1, | ||
47 | }, | ||
48 | { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_DEVICE_ID_CREATIVE_20K2), | ||
49 | .driver_data = ATC20K2, | ||
50 | }, | ||
51 | { 0, } | ||
52 | }; | ||
53 | MODULE_DEVICE_TABLE(pci, ct_pci_dev_ids); | ||
54 | |||
55 | static int __devinit | ||
56 | ct_card_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | ||
57 | { | ||
58 | static int dev; | ||
59 | struct snd_card *card; | ||
60 | struct ct_atc *atc; | ||
61 | int err; | ||
62 | |||
63 | if (dev >= SNDRV_CARDS) | ||
64 | return -ENODEV; | ||
65 | |||
66 | if (!enable[dev]) { | ||
67 | dev++; | ||
68 | return -ENOENT; | ||
69 | } | ||
70 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | ||
71 | if (err) | ||
72 | return err; | ||
73 | if ((reference_rate != 48000) && (reference_rate != 44100)) { | ||
74 | printk(KERN_ERR "ctxfi: Invalid reference_rate value %u!!!\n", | ||
75 | reference_rate); | ||
76 | printk(KERN_ERR "ctxfi: The valid values for reference_rate " | ||
77 | "are 48000 and 44100, Value 48000 is assumed.\n"); | ||
78 | reference_rate = 48000; | ||
79 | } | ||
80 | if ((multiple != 1) && (multiple != 2)) { | ||
81 | printk(KERN_ERR "ctxfi: Invalid multiple value %u!!!\n", | ||
82 | multiple); | ||
83 | printk(KERN_ERR "ctxfi: The valid values for multiple are " | ||
84 | "1 and 2, Value 2 is assumed.\n"); | ||
85 | multiple = 2; | ||
86 | } | ||
87 | err = ct_atc_create(card, pci, reference_rate, multiple, | ||
88 | pci_id->driver_data, &atc); | ||
89 | if (err < 0) | ||
90 | goto error; | ||
91 | |||
92 | card->private_data = atc; | ||
93 | |||
94 | /* Create alsa devices supported by this card */ | ||
95 | err = ct_atc_create_alsa_devs(atc); | ||
96 | if (err < 0) | ||
97 | goto error; | ||
98 | |||
99 | strcpy(card->driver, "SB-XFi"); | ||
100 | strcpy(card->shortname, "Creative X-Fi"); | ||
101 | snprintf(card->longname, sizeof(card->longname), "%s %s %s", | ||
102 | card->shortname, atc->chip_name, atc->model_name); | ||
103 | |||
104 | err = snd_card_register(card); | ||
105 | if (err < 0) | ||
106 | goto error; | ||
107 | |||
108 | pci_set_drvdata(pci, card); | ||
109 | dev++; | ||
110 | |||
111 | return 0; | ||
112 | |||
113 | error: | ||
114 | snd_card_free(card); | ||
115 | return err; | ||
116 | } | ||
117 | |||
118 | static void __devexit ct_card_remove(struct pci_dev *pci) | ||
119 | { | ||
120 | snd_card_free(pci_get_drvdata(pci)); | ||
121 | pci_set_drvdata(pci, NULL); | ||
122 | } | ||
123 | |||
124 | static struct pci_driver ct_driver = { | ||
125 | .name = "SB-XFi", | ||
126 | .id_table = ct_pci_dev_ids, | ||
127 | .probe = ct_card_probe, | ||
128 | .remove = __devexit_p(ct_card_remove), | ||
129 | }; | ||
130 | |||
131 | static int __init ct_card_init(void) | ||
132 | { | ||
133 | return pci_register_driver(&ct_driver); | ||
134 | } | ||
135 | |||
136 | static void __exit ct_card_exit(void) | ||
137 | { | ||
138 | pci_unregister_driver(&ct_driver); | ||
139 | } | ||
140 | |||
141 | module_init(ct_card_init) | ||
142 | module_exit(ct_card_exit) | ||
diff --git a/sound/pci/emu10k1/Makefile b/sound/pci/emu10k1/Makefile index cf2d5636d8be..fc5591e7777e 100644 --- a/sound/pci/emu10k1/Makefile +++ b/sound/pci/emu10k1/Makefile | |||
@@ -9,15 +9,7 @@ snd-emu10k1-objs := emu10k1.o emu10k1_main.o \ | |||
9 | snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o | 9 | snd-emu10k1-synth-objs := emu10k1_synth.o emu10k1_callback.o emu10k1_patch.o |
10 | snd-emu10k1x-objs := emu10k1x.o | 10 | snd-emu10k1x-objs := emu10k1x.o |
11 | 11 | ||
12 | # | ||
13 | # this function returns: | ||
14 | # "m" - CONFIG_SND_SEQUENCER is m | ||
15 | # <empty string> - CONFIG_SND_SEQUENCER is undefined | ||
16 | # otherwise parameter #1 value | ||
17 | # | ||
18 | sequencer = $(if $(subst y,,$(CONFIG_SND_SEQUENCER)),$(if $(1),m),$(if $(CONFIG_SND_SEQUENCER),$(1))) | ||
19 | |||
20 | # Toplevel Module Dependency | 12 | # Toplevel Module Dependency |
21 | obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o | 13 | obj-$(CONFIG_SND_EMU10K1) += snd-emu10k1.o |
22 | obj-$(call sequencer,$(CONFIG_SND_EMU10K1)) += snd-emu10k1-synth.o | 14 | obj-$(CONFIG_SND_EMU10K1_SEQ) += snd-emu10k1-synth.o |
23 | obj-$(CONFIG_SND_EMU10K1X) += snd-emu10k1x.o | 15 | obj-$(CONFIG_SND_EMU10K1X) += snd-emu10k1x.o |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 1970f0e70f37..4d3ad793e98f 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -858,7 +858,6 @@ static int __devinit snd_emu10k1x_pcm(struct emu10k1x *emu, int device, struct s | |||
858 | } | 858 | } |
859 | 859 | ||
860 | pcm->info_flags = 0; | 860 | pcm->info_flags = 0; |
861 | pcm->dev_subclass = SNDRV_PCM_SUBCLASS_GENERIC_MIX; | ||
862 | switch(device) { | 861 | switch(device) { |
863 | case 0: | 862 | case 0: |
864 | strcpy(pcm->name, "EMU10K1X Front"); | 863 | strcpy(pcm->name, "EMU10K1X Front"); |
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index 78f62fd404c2..55b83ef73c63 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -1736,7 +1736,7 @@ static struct snd_pcm_hardware snd_emu10k1_fx8010_playback = | |||
1736 | .buffer_bytes_max = (128*1024), | 1736 | .buffer_bytes_max = (128*1024), |
1737 | .period_bytes_min = 1024, | 1737 | .period_bytes_min = 1024, |
1738 | .period_bytes_max = (128*1024), | 1738 | .period_bytes_max = (128*1024), |
1739 | .periods_min = 1, | 1739 | .periods_min = 2, |
1740 | .periods_max = 1024, | 1740 | .periods_max = 1024, |
1741 | .fifo_size = 0, | 1741 | .fifo_size = 0, |
1742 | }; | 1742 | }; |
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index eb2a19b894a0..c710150d5065 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
@@ -139,6 +139,19 @@ config SND_HDA_CODEC_CONEXANT | |||
139 | snd-hda-codec-conexant. | 139 | snd-hda-codec-conexant. |
140 | This module is automatically loaded at probing. | 140 | This module is automatically loaded at probing. |
141 | 141 | ||
142 | config SND_HDA_CODEC_CA0110 | ||
143 | bool "Build Creative CA0110-IBG codec support" | ||
144 | depends on SND_HDA_INTEL | ||
145 | default y | ||
146 | help | ||
147 | Say Y here to include Creative CA0110-IBG codec support in | ||
148 | snd-hda-intel driver, found on some Creative X-Fi cards. | ||
149 | |||
150 | When the HD-audio driver is built as a module, the codec | ||
151 | support code is also built as another module, | ||
152 | snd-hda-codec-ca0110. | ||
153 | This module is automatically loaded at probing. | ||
154 | |||
142 | config SND_HDA_CODEC_CMEDIA | 155 | config SND_HDA_CODEC_CMEDIA |
143 | bool "Build C-Media HD-audio codec support" | 156 | bool "Build C-Media HD-audio codec support" |
144 | default y | 157 | default y |
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile index 50f9d0967251..e3081d4586cc 100644 --- a/sound/pci/hda/Makefile +++ b/sound/pci/hda/Makefile | |||
@@ -13,6 +13,7 @@ snd-hda-codec-analog-objs := patch_analog.o | |||
13 | snd-hda-codec-idt-objs := patch_sigmatel.o | 13 | snd-hda-codec-idt-objs := patch_sigmatel.o |
14 | snd-hda-codec-si3054-objs := patch_si3054.o | 14 | snd-hda-codec-si3054-objs := patch_si3054.o |
15 | snd-hda-codec-atihdmi-objs := patch_atihdmi.o | 15 | snd-hda-codec-atihdmi-objs := patch_atihdmi.o |
16 | snd-hda-codec-ca0110-objs := patch_ca0110.o | ||
16 | snd-hda-codec-conexant-objs := patch_conexant.o | 17 | snd-hda-codec-conexant-objs := patch_conexant.o |
17 | snd-hda-codec-via-objs := patch_via.o | 18 | snd-hda-codec-via-objs := patch_via.o |
18 | snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o | 19 | snd-hda-codec-nvhdmi-objs := patch_nvhdmi.o |
@@ -40,6 +41,9 @@ endif | |||
40 | ifdef CONFIG_SND_HDA_CODEC_ATIHDMI | 41 | ifdef CONFIG_SND_HDA_CODEC_ATIHDMI |
41 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o | 42 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-atihdmi.o |
42 | endif | 43 | endif |
44 | ifdef CONFIG_SND_HDA_CODEC_CA0110 | ||
45 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-ca0110.o | ||
46 | endif | ||
43 | ifdef CONFIG_SND_HDA_CODEC_CONEXANT | 47 | ifdef CONFIG_SND_HDA_CODEC_CONEXANT |
44 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o | 48 | obj-$(CONFIG_SND_HDA_INTEL) += snd-hda-codec-conexant.o |
45 | endif | 49 | endif |
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c index 4de5bacd3929..29272f2e95a0 100644 --- a/sound/pci/hda/hda_beep.c +++ b/sound/pci/hda/hda_beep.c | |||
@@ -45,6 +45,46 @@ static void snd_hda_generate_beep(struct work_struct *work) | |||
45 | AC_VERB_SET_BEEP_CONTROL, beep->tone); | 45 | AC_VERB_SET_BEEP_CONTROL, beep->tone); |
46 | } | 46 | } |
47 | 47 | ||
48 | /* (non-standard) Linear beep tone calculation for IDT/STAC codecs | ||
49 | * | ||
50 | * The tone frequency of beep generator on IDT/STAC codecs is | ||
51 | * defined from the 8bit tone parameter, in Hz, | ||
52 | * freq = 48000 * (257 - tone) / 1024 | ||
53 | * that is from 12kHz to 93.75kHz in step of 46.875 hz | ||
54 | */ | ||
55 | static int beep_linear_tone(struct hda_beep *beep, int hz) | ||
56 | { | ||
57 | hz *= 1000; /* fixed point */ | ||
58 | hz = hz - DIGBEEP_HZ_MIN; | ||
59 | if (hz < 0) | ||
60 | hz = 0; /* turn off PC beep*/ | ||
61 | else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) | ||
62 | hz = 0xff; | ||
63 | else { | ||
64 | hz /= DIGBEEP_HZ_STEP; | ||
65 | hz++; | ||
66 | } | ||
67 | return hz; | ||
68 | } | ||
69 | |||
70 | /* HD-audio standard beep tone parameter calculation | ||
71 | * | ||
72 | * The tone frequency in Hz is calculated as | ||
73 | * freq = 48000 / (tone * 4) | ||
74 | * from 47Hz to 12kHz | ||
75 | */ | ||
76 | static int beep_standard_tone(struct hda_beep *beep, int hz) | ||
77 | { | ||
78 | if (hz <= 0) | ||
79 | return 0; /* disabled */ | ||
80 | hz = 12000 / hz; | ||
81 | if (hz > 0xff) | ||
82 | return 0xff; | ||
83 | if (hz <= 0) | ||
84 | return 1; | ||
85 | return hz; | ||
86 | } | ||
87 | |||
48 | static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, | 88 | static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, |
49 | unsigned int code, int hz) | 89 | unsigned int code, int hz) |
50 | { | 90 | { |
@@ -55,21 +95,14 @@ static int snd_hda_beep_event(struct input_dev *dev, unsigned int type, | |||
55 | if (hz) | 95 | if (hz) |
56 | hz = 1000; | 96 | hz = 1000; |
57 | case SND_TONE: | 97 | case SND_TONE: |
58 | hz *= 1000; /* fixed point */ | 98 | if (beep->linear_tone) |
59 | hz = hz - DIGBEEP_HZ_MIN; | 99 | beep->tone = beep_linear_tone(beep, hz); |
60 | if (hz < 0) | 100 | else |
61 | hz = 0; /* turn off PC beep*/ | 101 | beep->tone = beep_standard_tone(beep, hz); |
62 | else if (hz >= (DIGBEEP_HZ_MAX - DIGBEEP_HZ_MIN)) | ||
63 | hz = 0xff; | ||
64 | else { | ||
65 | hz /= DIGBEEP_HZ_STEP; | ||
66 | hz++; | ||
67 | } | ||
68 | break; | 102 | break; |
69 | default: | 103 | default: |
70 | return -1; | 104 | return -1; |
71 | } | 105 | } |
72 | beep->tone = hz; | ||
73 | 106 | ||
74 | /* schedule beep event */ | 107 | /* schedule beep event */ |
75 | schedule_work(&beep->beep_work); | 108 | schedule_work(&beep->beep_work); |
diff --git a/sound/pci/hda/hda_beep.h b/sound/pci/hda/hda_beep.h index 51bf6a5daf39..0c3de787c717 100644 --- a/sound/pci/hda/hda_beep.h +++ b/sound/pci/hda/hda_beep.h | |||
@@ -30,8 +30,9 @@ struct hda_beep { | |||
30 | struct hda_codec *codec; | 30 | struct hda_codec *codec; |
31 | char phys[32]; | 31 | char phys[32]; |
32 | int tone; | 32 | int tone; |
33 | int nid; | 33 | hda_nid_t nid; |
34 | int enabled; | 34 | unsigned int enabled:1; |
35 | unsigned int linear_tone:1; /* linear tone for IDT/STAC codec */ | ||
35 | struct work_struct beep_work; /* scheduled task for beep event */ | 36 | struct work_struct beep_work; /* scheduled task for beep event */ |
36 | }; | 37 | }; |
37 | 38 | ||
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 8820faf6c9d8..562403a23488 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -48,6 +48,7 @@ static struct hda_vendor_id hda_vendor_ids[] = { | |||
48 | { 0x1095, "Silicon Image" }, | 48 | { 0x1095, "Silicon Image" }, |
49 | { 0x10de, "Nvidia" }, | 49 | { 0x10de, "Nvidia" }, |
50 | { 0x10ec, "Realtek" }, | 50 | { 0x10ec, "Realtek" }, |
51 | { 0x1102, "Creative" }, | ||
51 | { 0x1106, "VIA" }, | 52 | { 0x1106, "VIA" }, |
52 | { 0x111d, "IDT" }, | 53 | { 0x111d, "IDT" }, |
53 | { 0x11c1, "LSI" }, | 54 | { 0x11c1, "LSI" }, |
@@ -157,6 +158,39 @@ make_codec_cmd(struct hda_codec *codec, hda_nid_t nid, int direct, | |||
157 | return val; | 158 | return val; |
158 | } | 159 | } |
159 | 160 | ||
161 | /* | ||
162 | * Send and receive a verb | ||
163 | */ | ||
164 | static int codec_exec_verb(struct hda_codec *codec, unsigned int cmd, | ||
165 | unsigned int *res) | ||
166 | { | ||
167 | struct hda_bus *bus = codec->bus; | ||
168 | int err; | ||
169 | |||
170 | if (res) | ||
171 | *res = -1; | ||
172 | again: | ||
173 | snd_hda_power_up(codec); | ||
174 | mutex_lock(&bus->cmd_mutex); | ||
175 | err = bus->ops.command(bus, cmd); | ||
176 | if (!err && res) | ||
177 | *res = bus->ops.get_response(bus); | ||
178 | mutex_unlock(&bus->cmd_mutex); | ||
179 | snd_hda_power_down(codec); | ||
180 | if (res && *res == -1 && bus->rirb_error) { | ||
181 | if (bus->response_reset) { | ||
182 | snd_printd("hda_codec: resetting BUS due to " | ||
183 | "fatal communication error\n"); | ||
184 | bus->ops.bus_reset(bus); | ||
185 | } | ||
186 | goto again; | ||
187 | } | ||
188 | /* clear reset-flag when the communication gets recovered */ | ||
189 | if (!err) | ||
190 | bus->response_reset = 0; | ||
191 | return err; | ||
192 | } | ||
193 | |||
160 | /** | 194 | /** |
161 | * snd_hda_codec_read - send a command and get the response | 195 | * snd_hda_codec_read - send a command and get the response |
162 | * @codec: the HDA codec | 196 | * @codec: the HDA codec |
@@ -173,18 +207,9 @@ unsigned int snd_hda_codec_read(struct hda_codec *codec, hda_nid_t nid, | |||
173 | int direct, | 207 | int direct, |
174 | unsigned int verb, unsigned int parm) | 208 | unsigned int verb, unsigned int parm) |
175 | { | 209 | { |
176 | struct hda_bus *bus = codec->bus; | 210 | unsigned cmd = make_codec_cmd(codec, nid, direct, verb, parm); |
177 | unsigned int res; | 211 | unsigned int res; |
178 | 212 | codec_exec_verb(codec, cmd, &res); | |
179 | res = make_codec_cmd(codec, nid, direct, verb, parm); | ||
180 | snd_hda_power_up(codec); | ||
181 | mutex_lock(&bus->cmd_mutex); | ||
182 | if (!bus->ops.command(bus, res)) | ||
183 | res = bus->ops.get_response(bus); | ||
184 | else | ||
185 | res = (unsigned int)-1; | ||
186 | mutex_unlock(&bus->cmd_mutex); | ||
187 | snd_hda_power_down(codec); | ||
188 | return res; | 213 | return res; |
189 | } | 214 | } |
190 | EXPORT_SYMBOL_HDA(snd_hda_codec_read); | 215 | EXPORT_SYMBOL_HDA(snd_hda_codec_read); |
@@ -204,17 +229,10 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_read); | |||
204 | int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, | 229 | int snd_hda_codec_write(struct hda_codec *codec, hda_nid_t nid, int direct, |
205 | unsigned int verb, unsigned int parm) | 230 | unsigned int verb, unsigned int parm) |
206 | { | 231 | { |
207 | struct hda_bus *bus = codec->bus; | 232 | unsigned int cmd = make_codec_cmd(codec, nid, direct, verb, parm); |
208 | unsigned int res; | 233 | unsigned int res; |
209 | int err; | 234 | return codec_exec_verb(codec, cmd, |
210 | 235 | codec->bus->sync_write ? &res : NULL); | |
211 | res = make_codec_cmd(codec, nid, direct, verb, parm); | ||
212 | snd_hda_power_up(codec); | ||
213 | mutex_lock(&bus->cmd_mutex); | ||
214 | err = bus->ops.command(bus, res); | ||
215 | mutex_unlock(&bus->cmd_mutex); | ||
216 | snd_hda_power_down(codec); | ||
217 | return err; | ||
218 | } | 236 | } |
219 | EXPORT_SYMBOL_HDA(snd_hda_codec_write); | 237 | EXPORT_SYMBOL_HDA(snd_hda_codec_write); |
220 | 238 | ||
@@ -613,7 +631,10 @@ static int get_codec_name(struct hda_codec *codec) | |||
613 | const struct hda_vendor_id *c; | 631 | const struct hda_vendor_id *c; |
614 | const char *vendor = NULL; | 632 | const char *vendor = NULL; |
615 | u16 vendor_id = codec->vendor_id >> 16; | 633 | u16 vendor_id = codec->vendor_id >> 16; |
616 | char tmp[16], name[32]; | 634 | char tmp[16]; |
635 | |||
636 | if (codec->vendor_name) | ||
637 | goto get_chip_name; | ||
617 | 638 | ||
618 | for (c = hda_vendor_ids; c->id; c++) { | 639 | for (c = hda_vendor_ids; c->id; c++) { |
619 | if (c->id == vendor_id) { | 640 | if (c->id == vendor_id) { |
@@ -625,14 +646,21 @@ static int get_codec_name(struct hda_codec *codec) | |||
625 | sprintf(tmp, "Generic %04x", vendor_id); | 646 | sprintf(tmp, "Generic %04x", vendor_id); |
626 | vendor = tmp; | 647 | vendor = tmp; |
627 | } | 648 | } |
649 | codec->vendor_name = kstrdup(vendor, GFP_KERNEL); | ||
650 | if (!codec->vendor_name) | ||
651 | return -ENOMEM; | ||
652 | |||
653 | get_chip_name: | ||
654 | if (codec->chip_name) | ||
655 | return 0; | ||
656 | |||
628 | if (codec->preset && codec->preset->name) | 657 | if (codec->preset && codec->preset->name) |
629 | snprintf(name, sizeof(name), "%s %s", vendor, | 658 | codec->chip_name = kstrdup(codec->preset->name, GFP_KERNEL); |
630 | codec->preset->name); | 659 | else { |
631 | else | 660 | sprintf(tmp, "ID %x", codec->vendor_id & 0xffff); |
632 | snprintf(name, sizeof(name), "%s ID %x", vendor, | 661 | codec->chip_name = kstrdup(tmp, GFP_KERNEL); |
633 | codec->vendor_id & 0xffff); | 662 | } |
634 | codec->name = kstrdup(name, GFP_KERNEL); | 663 | if (!codec->chip_name) |
635 | if (!codec->name) | ||
636 | return -ENOMEM; | 664 | return -ENOMEM; |
637 | return 0; | 665 | return 0; |
638 | } | 666 | } |
@@ -838,7 +866,8 @@ static void snd_hda_codec_free(struct hda_codec *codec) | |||
838 | module_put(codec->owner); | 866 | module_put(codec->owner); |
839 | free_hda_cache(&codec->amp_cache); | 867 | free_hda_cache(&codec->amp_cache); |
840 | free_hda_cache(&codec->cmd_cache); | 868 | free_hda_cache(&codec->cmd_cache); |
841 | kfree(codec->name); | 869 | kfree(codec->vendor_name); |
870 | kfree(codec->chip_name); | ||
842 | kfree(codec->modelname); | 871 | kfree(codec->modelname); |
843 | kfree(codec->wcaps); | 872 | kfree(codec->wcaps); |
844 | kfree(codec); | 873 | kfree(codec); |
@@ -979,15 +1008,16 @@ int snd_hda_codec_configure(struct hda_codec *codec) | |||
979 | int err; | 1008 | int err; |
980 | 1009 | ||
981 | codec->preset = find_codec_preset(codec); | 1010 | codec->preset = find_codec_preset(codec); |
982 | if (!codec->name) { | 1011 | if (!codec->vendor_name || !codec->chip_name) { |
983 | err = get_codec_name(codec); | 1012 | err = get_codec_name(codec); |
984 | if (err < 0) | 1013 | if (err < 0) |
985 | return err; | 1014 | return err; |
986 | } | 1015 | } |
987 | /* audio codec should override the mixer name */ | 1016 | /* audio codec should override the mixer name */ |
988 | if (codec->afg || !*codec->bus->card->mixername) | 1017 | if (codec->afg || !*codec->bus->card->mixername) |
989 | strlcpy(codec->bus->card->mixername, codec->name, | 1018 | snprintf(codec->bus->card->mixername, |
990 | sizeof(codec->bus->card->mixername)); | 1019 | sizeof(codec->bus->card->mixername), |
1020 | "%s %s", codec->vendor_name, codec->chip_name); | ||
991 | 1021 | ||
992 | if (is_generic_config(codec)) { | 1022 | if (is_generic_config(codec)) { |
993 | err = snd_hda_parse_generic_codec(codec); | 1023 | err = snd_hda_parse_generic_codec(codec); |
@@ -1055,6 +1085,8 @@ EXPORT_SYMBOL_HDA(snd_hda_codec_cleanup_stream); | |||
1055 | /* FIXME: more better hash key? */ | 1085 | /* FIXME: more better hash key? */ |
1056 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) | 1086 | #define HDA_HASH_KEY(nid,dir,idx) (u32)((nid) + ((idx) << 16) + ((dir) << 24)) |
1057 | #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) | 1087 | #define HDA_HASH_PINCAP_KEY(nid) (u32)((nid) + (0x02 << 24)) |
1088 | #define HDA_HASH_PARPCM_KEY(nid) (u32)((nid) + (0x03 << 24)) | ||
1089 | #define HDA_HASH_PARSTR_KEY(nid) (u32)((nid) + (0x04 << 24)) | ||
1058 | #define INFO_AMP_CAPS (1<<0) | 1090 | #define INFO_AMP_CAPS (1<<0) |
1059 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) | 1091 | #define INFO_AMP_VOL(ch) (1 << (1 + (ch))) |
1060 | 1092 | ||
@@ -1145,19 +1177,32 @@ int snd_hda_override_amp_caps(struct hda_codec *codec, hda_nid_t nid, int dir, | |||
1145 | } | 1177 | } |
1146 | EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); | 1178 | EXPORT_SYMBOL_HDA(snd_hda_override_amp_caps); |
1147 | 1179 | ||
1148 | u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) | 1180 | static unsigned int |
1181 | query_caps_hash(struct hda_codec *codec, hda_nid_t nid, u32 key, | ||
1182 | unsigned int (*func)(struct hda_codec *, hda_nid_t)) | ||
1149 | { | 1183 | { |
1150 | struct hda_amp_info *info; | 1184 | struct hda_amp_info *info; |
1151 | 1185 | ||
1152 | info = get_alloc_amp_hash(codec, HDA_HASH_PINCAP_KEY(nid)); | 1186 | info = get_alloc_amp_hash(codec, key); |
1153 | if (!info) | 1187 | if (!info) |
1154 | return 0; | 1188 | return 0; |
1155 | if (!info->head.val) { | 1189 | if (!info->head.val) { |
1156 | info->amp_caps = snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
1157 | info->head.val |= INFO_AMP_CAPS; | 1190 | info->head.val |= INFO_AMP_CAPS; |
1191 | info->amp_caps = func(codec, nid); | ||
1158 | } | 1192 | } |
1159 | return info->amp_caps; | 1193 | return info->amp_caps; |
1160 | } | 1194 | } |
1195 | |||
1196 | static unsigned int read_pin_cap(struct hda_codec *codec, hda_nid_t nid) | ||
1197 | { | ||
1198 | return snd_hda_param_read(codec, nid, AC_PAR_PIN_CAP); | ||
1199 | } | ||
1200 | |||
1201 | u32 snd_hda_query_pin_caps(struct hda_codec *codec, hda_nid_t nid) | ||
1202 | { | ||
1203 | return query_caps_hash(codec, nid, HDA_HASH_PINCAP_KEY(nid), | ||
1204 | read_pin_cap); | ||
1205 | } | ||
1161 | EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); | 1206 | EXPORT_SYMBOL_HDA(snd_hda_query_pin_caps); |
1162 | 1207 | ||
1163 | /* | 1208 | /* |
@@ -1432,6 +1477,8 @@ _snd_hda_find_mixer_ctl(struct hda_codec *codec, | |||
1432 | memset(&id, 0, sizeof(id)); | 1477 | memset(&id, 0, sizeof(id)); |
1433 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; | 1478 | id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; |
1434 | id.index = idx; | 1479 | id.index = idx; |
1480 | if (snd_BUG_ON(strlen(name) >= sizeof(id.name))) | ||
1481 | return NULL; | ||
1435 | strcpy(id.name, name); | 1482 | strcpy(id.name, name); |
1436 | return snd_ctl_find_id(codec->bus->card, &id); | 1483 | return snd_ctl_find_id(codec->bus->card, &id); |
1437 | } | 1484 | } |
@@ -2242,28 +2289,22 @@ EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); | |||
2242 | int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, | 2289 | int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, |
2243 | int direct, unsigned int verb, unsigned int parm) | 2290 | int direct, unsigned int verb, unsigned int parm) |
2244 | { | 2291 | { |
2245 | struct hda_bus *bus = codec->bus; | 2292 | int err = snd_hda_codec_write(codec, nid, direct, verb, parm); |
2246 | unsigned int res; | 2293 | struct hda_cache_head *c; |
2247 | int err; | 2294 | u32 key; |
2248 | 2295 | ||
2249 | res = make_codec_cmd(codec, nid, direct, verb, parm); | 2296 | if (err < 0) |
2250 | snd_hda_power_up(codec); | 2297 | return err; |
2251 | mutex_lock(&bus->cmd_mutex); | 2298 | /* parm may contain the verb stuff for get/set amp */ |
2252 | err = bus->ops.command(bus, res); | 2299 | verb = verb | (parm >> 8); |
2253 | if (!err) { | 2300 | parm &= 0xff; |
2254 | struct hda_cache_head *c; | 2301 | key = build_cmd_cache_key(nid, verb); |
2255 | u32 key; | 2302 | mutex_lock(&codec->bus->cmd_mutex); |
2256 | /* parm may contain the verb stuff for get/set amp */ | 2303 | c = get_alloc_hash(&codec->cmd_cache, key); |
2257 | verb = verb | (parm >> 8); | 2304 | if (c) |
2258 | parm &= 0xff; | 2305 | c->val = parm; |
2259 | key = build_cmd_cache_key(nid, verb); | 2306 | mutex_unlock(&codec->bus->cmd_mutex); |
2260 | c = get_alloc_hash(&codec->cmd_cache, key); | 2307 | return 0; |
2261 | if (c) | ||
2262 | c->val = parm; | ||
2263 | } | ||
2264 | mutex_unlock(&bus->cmd_mutex); | ||
2265 | snd_hda_power_down(codec); | ||
2266 | return err; | ||
2267 | } | 2308 | } |
2268 | EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); | 2309 | EXPORT_SYMBOL_HDA(snd_hda_codec_write_cache); |
2269 | 2310 | ||
@@ -2321,7 +2362,8 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
2321 | if (wcaps & AC_WCAP_POWER) { | 2362 | if (wcaps & AC_WCAP_POWER) { |
2322 | unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> | 2363 | unsigned int wid_type = (wcaps & AC_WCAP_TYPE) >> |
2323 | AC_WCAP_TYPE_SHIFT; | 2364 | AC_WCAP_TYPE_SHIFT; |
2324 | if (wid_type == AC_WID_PIN) { | 2365 | if (power_state == AC_PWRST_D3 && |
2366 | wid_type == AC_WID_PIN) { | ||
2325 | unsigned int pincap; | 2367 | unsigned int pincap; |
2326 | /* | 2368 | /* |
2327 | * don't power down the widget if it controls | 2369 | * don't power down the widget if it controls |
@@ -2333,7 +2375,7 @@ static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, | |||
2333 | nid, 0, | 2375 | nid, 0, |
2334 | AC_VERB_GET_EAPD_BTLENABLE, 0); | 2376 | AC_VERB_GET_EAPD_BTLENABLE, 0); |
2335 | eapd &= 0x02; | 2377 | eapd &= 0x02; |
2336 | if (power_state == AC_PWRST_D3 && eapd) | 2378 | if (eapd) |
2337 | continue; | 2379 | continue; |
2338 | } | 2380 | } |
2339 | } | 2381 | } |
@@ -2544,6 +2586,41 @@ unsigned int snd_hda_calc_stream_format(unsigned int rate, | |||
2544 | } | 2586 | } |
2545 | EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); | 2587 | EXPORT_SYMBOL_HDA(snd_hda_calc_stream_format); |
2546 | 2588 | ||
2589 | static unsigned int get_pcm_param(struct hda_codec *codec, hda_nid_t nid) | ||
2590 | { | ||
2591 | unsigned int val = 0; | ||
2592 | if (nid != codec->afg && | ||
2593 | (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) | ||
2594 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
2595 | if (!val || val == -1) | ||
2596 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2597 | if (!val || val == -1) | ||
2598 | return 0; | ||
2599 | return val; | ||
2600 | } | ||
2601 | |||
2602 | static unsigned int query_pcm_param(struct hda_codec *codec, hda_nid_t nid) | ||
2603 | { | ||
2604 | return query_caps_hash(codec, nid, HDA_HASH_PARPCM_KEY(nid), | ||
2605 | get_pcm_param); | ||
2606 | } | ||
2607 | |||
2608 | static unsigned int get_stream_param(struct hda_codec *codec, hda_nid_t nid) | ||
2609 | { | ||
2610 | unsigned int streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | ||
2611 | if (!streams || streams == -1) | ||
2612 | streams = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); | ||
2613 | if (!streams || streams == -1) | ||
2614 | return 0; | ||
2615 | return streams; | ||
2616 | } | ||
2617 | |||
2618 | static unsigned int query_stream_param(struct hda_codec *codec, hda_nid_t nid) | ||
2619 | { | ||
2620 | return query_caps_hash(codec, nid, HDA_HASH_PARSTR_KEY(nid), | ||
2621 | get_stream_param); | ||
2622 | } | ||
2623 | |||
2547 | /** | 2624 | /** |
2548 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats | 2625 | * snd_hda_query_supported_pcm - query the supported PCM rates and formats |
2549 | * @codec: the HDA codec | 2626 | * @codec: the HDA codec |
@@ -2562,15 +2639,8 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
2562 | { | 2639 | { |
2563 | unsigned int i, val, wcaps; | 2640 | unsigned int i, val, wcaps; |
2564 | 2641 | ||
2565 | val = 0; | ||
2566 | wcaps = get_wcaps(codec, nid); | 2642 | wcaps = get_wcaps(codec, nid); |
2567 | if (nid != codec->afg && (wcaps & AC_WCAP_FORMAT_OVRD)) { | 2643 | val = query_pcm_param(codec, nid); |
2568 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | ||
2569 | if (val == -1) | ||
2570 | return -EIO; | ||
2571 | } | ||
2572 | if (!val) | ||
2573 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2574 | 2644 | ||
2575 | if (ratesp) { | 2645 | if (ratesp) { |
2576 | u32 rates = 0; | 2646 | u32 rates = 0; |
@@ -2592,15 +2662,9 @@ static int snd_hda_query_supported_pcm(struct hda_codec *codec, hda_nid_t nid, | |||
2592 | u64 formats = 0; | 2662 | u64 formats = 0; |
2593 | unsigned int streams, bps; | 2663 | unsigned int streams, bps; |
2594 | 2664 | ||
2595 | streams = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | 2665 | streams = query_stream_param(codec, nid); |
2596 | if (streams == -1) | 2666 | if (!streams) |
2597 | return -EIO; | 2667 | return -EIO; |
2598 | if (!streams) { | ||
2599 | streams = snd_hda_param_read(codec, codec->afg, | ||
2600 | AC_PAR_STREAM); | ||
2601 | if (streams == -1) | ||
2602 | return -EIO; | ||
2603 | } | ||
2604 | 2668 | ||
2605 | bps = 0; | 2669 | bps = 0; |
2606 | if (streams & AC_SUPFMT_PCM) { | 2670 | if (streams & AC_SUPFMT_PCM) { |
@@ -2674,17 +2738,9 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
2674 | int i; | 2738 | int i; |
2675 | unsigned int val = 0, rate, stream; | 2739 | unsigned int val = 0, rate, stream; |
2676 | 2740 | ||
2677 | if (nid != codec->afg && | 2741 | val = query_pcm_param(codec, nid); |
2678 | (get_wcaps(codec, nid) & AC_WCAP_FORMAT_OVRD)) { | 2742 | if (!val) |
2679 | val = snd_hda_param_read(codec, nid, AC_PAR_PCM); | 2743 | return 0; |
2680 | if (val == -1) | ||
2681 | return 0; | ||
2682 | } | ||
2683 | if (!val) { | ||
2684 | val = snd_hda_param_read(codec, codec->afg, AC_PAR_PCM); | ||
2685 | if (val == -1) | ||
2686 | return 0; | ||
2687 | } | ||
2688 | 2744 | ||
2689 | rate = format & 0xff00; | 2745 | rate = format & 0xff00; |
2690 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) | 2746 | for (i = 0; i < AC_PAR_PCM_RATE_BITS; i++) |
@@ -2696,12 +2752,8 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, | |||
2696 | if (i >= AC_PAR_PCM_RATE_BITS) | 2752 | if (i >= AC_PAR_PCM_RATE_BITS) |
2697 | return 0; | 2753 | return 0; |
2698 | 2754 | ||
2699 | stream = snd_hda_param_read(codec, nid, AC_PAR_STREAM); | 2755 | stream = query_stream_param(codec, nid); |
2700 | if (stream == -1) | 2756 | if (!stream) |
2701 | return 0; | ||
2702 | if (!stream && nid != codec->afg) | ||
2703 | stream = snd_hda_param_read(codec, codec->afg, AC_PAR_STREAM); | ||
2704 | if (!stream || stream == -1) | ||
2705 | return 0; | 2757 | return 0; |
2706 | 2758 | ||
2707 | if (stream & AC_SUPFMT_PCM) { | 2759 | if (stream & AC_SUPFMT_PCM) { |
@@ -3835,11 +3887,10 @@ EXPORT_SYMBOL_HDA(auto_pin_cfg_labels); | |||
3835 | /** | 3887 | /** |
3836 | * snd_hda_suspend - suspend the codecs | 3888 | * snd_hda_suspend - suspend the codecs |
3837 | * @bus: the HDA bus | 3889 | * @bus: the HDA bus |
3838 | * @state: suspsend state | ||
3839 | * | 3890 | * |
3840 | * Returns 0 if successful. | 3891 | * Returns 0 if successful. |
3841 | */ | 3892 | */ |
3842 | int snd_hda_suspend(struct hda_bus *bus, pm_message_t state) | 3893 | int snd_hda_suspend(struct hda_bus *bus) |
3843 | { | 3894 | { |
3844 | struct hda_codec *codec; | 3895 | struct hda_codec *codec; |
3845 | 3896 | ||
diff --git a/sound/pci/hda/hda_codec.h b/sound/pci/hda/hda_codec.h index 2fdecf4b0eb6..cad79efaabc9 100644 --- a/sound/pci/hda/hda_codec.h +++ b/sound/pci/hda/hda_codec.h | |||
@@ -574,6 +574,8 @@ struct hda_bus_ops { | |||
574 | /* attach a PCM stream */ | 574 | /* attach a PCM stream */ |
575 | int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, | 575 | int (*attach_pcm)(struct hda_bus *bus, struct hda_codec *codec, |
576 | struct hda_pcm *pcm); | 576 | struct hda_pcm *pcm); |
577 | /* reset bus for retry verb */ | ||
578 | void (*bus_reset)(struct hda_bus *bus); | ||
577 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 579 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
578 | /* notify power-up/down from codec to controller */ | 580 | /* notify power-up/down from codec to controller */ |
579 | void (*pm_notify)(struct hda_bus *bus); | 581 | void (*pm_notify)(struct hda_bus *bus); |
@@ -622,7 +624,13 @@ struct hda_bus { | |||
622 | 624 | ||
623 | /* misc op flags */ | 625 | /* misc op flags */ |
624 | unsigned int needs_damn_long_delay :1; | 626 | unsigned int needs_damn_long_delay :1; |
627 | unsigned int allow_bus_reset:1; /* allow bus reset at fatal error */ | ||
628 | unsigned int sync_write:1; /* sync after verb write */ | ||
629 | /* status for codec/controller */ | ||
625 | unsigned int shutdown :1; /* being unloaded */ | 630 | unsigned int shutdown :1; /* being unloaded */ |
631 | unsigned int rirb_error:1; /* error in codec communication */ | ||
632 | unsigned int response_reset:1; /* controller was reset */ | ||
633 | unsigned int in_reset:1; /* during reset operation */ | ||
626 | }; | 634 | }; |
627 | 635 | ||
628 | /* | 636 | /* |
@@ -747,7 +755,8 @@ struct hda_codec { | |||
747 | /* detected preset */ | 755 | /* detected preset */ |
748 | const struct hda_codec_preset *preset; | 756 | const struct hda_codec_preset *preset; |
749 | struct module *owner; | 757 | struct module *owner; |
750 | const char *name; /* codec name */ | 758 | const char *vendor_name; /* codec vendor name */ |
759 | const char *chip_name; /* codec chip name */ | ||
751 | const char *modelname; /* model name for preset */ | 760 | const char *modelname; /* model name for preset */ |
752 | 761 | ||
753 | /* set by patch */ | 762 | /* set by patch */ |
@@ -905,7 +914,7 @@ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); | |||
905 | * power management | 914 | * power management |
906 | */ | 915 | */ |
907 | #ifdef CONFIG_PM | 916 | #ifdef CONFIG_PM |
908 | int snd_hda_suspend(struct hda_bus *bus, pm_message_t state); | 917 | int snd_hda_suspend(struct hda_bus *bus); |
909 | int snd_hda_resume(struct hda_bus *bus); | 918 | int snd_hda_resume(struct hda_bus *bus); |
910 | #endif | 919 | #endif |
911 | 920 | ||
diff --git a/sound/pci/hda/hda_hwdep.c b/sound/pci/hda/hda_hwdep.c index 1c57505c2874..6812fbe80fa4 100644 --- a/sound/pci/hda/hda_hwdep.c +++ b/sound/pci/hda/hda_hwdep.c | |||
@@ -242,7 +242,8 @@ CODEC_INFO_SHOW(subsystem_id); | |||
242 | CODEC_INFO_SHOW(revision_id); | 242 | CODEC_INFO_SHOW(revision_id); |
243 | CODEC_INFO_SHOW(afg); | 243 | CODEC_INFO_SHOW(afg); |
244 | CODEC_INFO_SHOW(mfg); | 244 | CODEC_INFO_SHOW(mfg); |
245 | CODEC_INFO_STR_SHOW(name); | 245 | CODEC_INFO_STR_SHOW(vendor_name); |
246 | CODEC_INFO_STR_SHOW(chip_name); | ||
246 | CODEC_INFO_STR_SHOW(modelname); | 247 | CODEC_INFO_STR_SHOW(modelname); |
247 | 248 | ||
248 | #define CODEC_INFO_STORE(type) \ | 249 | #define CODEC_INFO_STORE(type) \ |
@@ -275,7 +276,8 @@ static ssize_t type##_store(struct device *dev, \ | |||
275 | CODEC_INFO_STORE(vendor_id); | 276 | CODEC_INFO_STORE(vendor_id); |
276 | CODEC_INFO_STORE(subsystem_id); | 277 | CODEC_INFO_STORE(subsystem_id); |
277 | CODEC_INFO_STORE(revision_id); | 278 | CODEC_INFO_STORE(revision_id); |
278 | CODEC_INFO_STR_STORE(name); | 279 | CODEC_INFO_STR_STORE(vendor_name); |
280 | CODEC_INFO_STR_STORE(chip_name); | ||
279 | CODEC_INFO_STR_STORE(modelname); | 281 | CODEC_INFO_STR_STORE(modelname); |
280 | 282 | ||
281 | #define CODEC_ACTION_STORE(type) \ | 283 | #define CODEC_ACTION_STORE(type) \ |
@@ -499,7 +501,8 @@ static struct device_attribute codec_attrs[] = { | |||
499 | CODEC_ATTR_RW(revision_id), | 501 | CODEC_ATTR_RW(revision_id), |
500 | CODEC_ATTR_RO(afg), | 502 | CODEC_ATTR_RO(afg), |
501 | CODEC_ATTR_RO(mfg), | 503 | CODEC_ATTR_RO(mfg), |
502 | CODEC_ATTR_RW(name), | 504 | CODEC_ATTR_RW(vendor_name), |
505 | CODEC_ATTR_RW(chip_name), | ||
503 | CODEC_ATTR_RW(modelname), | 506 | CODEC_ATTR_RW(modelname), |
504 | CODEC_ATTR_RW(init_verbs), | 507 | CODEC_ATTR_RW(init_verbs), |
505 | CODEC_ATTR_RW(hints), | 508 | CODEC_ATTR_RW(hints), |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 21e99cfa8c49..4e9ea7080270 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -128,21 +128,33 @@ MODULE_SUPPORTED_DEVICE("{{Intel, ICH6}," | |||
128 | "{ULI, M5461}}"); | 128 | "{ULI, M5461}}"); |
129 | MODULE_DESCRIPTION("Intel HDA driver"); | 129 | MODULE_DESCRIPTION("Intel HDA driver"); |
130 | 130 | ||
131 | #ifdef CONFIG_SND_VERBOSE_PRINTK | ||
132 | #define SFX /* nop */ | ||
133 | #else | ||
131 | #define SFX "hda-intel: " | 134 | #define SFX "hda-intel: " |
132 | 135 | #endif | |
133 | 136 | ||
134 | /* | 137 | /* |
135 | * registers | 138 | * registers |
136 | */ | 139 | */ |
137 | #define ICH6_REG_GCAP 0x00 | 140 | #define ICH6_REG_GCAP 0x00 |
141 | #define ICH6_GCAP_64OK (1 << 0) /* 64bit address support */ | ||
142 | #define ICH6_GCAP_NSDO (3 << 1) /* # of serial data out signals */ | ||
143 | #define ICH6_GCAP_BSS (31 << 3) /* # of bidirectional streams */ | ||
144 | #define ICH6_GCAP_ISS (15 << 8) /* # of input streams */ | ||
145 | #define ICH6_GCAP_OSS (15 << 12) /* # of output streams */ | ||
138 | #define ICH6_REG_VMIN 0x02 | 146 | #define ICH6_REG_VMIN 0x02 |
139 | #define ICH6_REG_VMAJ 0x03 | 147 | #define ICH6_REG_VMAJ 0x03 |
140 | #define ICH6_REG_OUTPAY 0x04 | 148 | #define ICH6_REG_OUTPAY 0x04 |
141 | #define ICH6_REG_INPAY 0x06 | 149 | #define ICH6_REG_INPAY 0x06 |
142 | #define ICH6_REG_GCTL 0x08 | 150 | #define ICH6_REG_GCTL 0x08 |
151 | #define ICH6_GCTL_RESET (1 << 0) /* controller reset */ | ||
152 | #define ICH6_GCTL_FCNTRL (1 << 1) /* flush control */ | ||
153 | #define ICH6_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */ | ||
143 | #define ICH6_REG_WAKEEN 0x0c | 154 | #define ICH6_REG_WAKEEN 0x0c |
144 | #define ICH6_REG_STATESTS 0x0e | 155 | #define ICH6_REG_STATESTS 0x0e |
145 | #define ICH6_REG_GSTS 0x10 | 156 | #define ICH6_REG_GSTS 0x10 |
157 | #define ICH6_GSTS_FSTS (1 << 1) /* flush status */ | ||
146 | #define ICH6_REG_INTCTL 0x20 | 158 | #define ICH6_REG_INTCTL 0x20 |
147 | #define ICH6_REG_INTSTS 0x24 | 159 | #define ICH6_REG_INTSTS 0x24 |
148 | #define ICH6_REG_WALCLK 0x30 | 160 | #define ICH6_REG_WALCLK 0x30 |
@@ -150,17 +162,27 @@ MODULE_DESCRIPTION("Intel HDA driver"); | |||
150 | #define ICH6_REG_CORBLBASE 0x40 | 162 | #define ICH6_REG_CORBLBASE 0x40 |
151 | #define ICH6_REG_CORBUBASE 0x44 | 163 | #define ICH6_REG_CORBUBASE 0x44 |
152 | #define ICH6_REG_CORBWP 0x48 | 164 | #define ICH6_REG_CORBWP 0x48 |
153 | #define ICH6_REG_CORBRP 0x4A | 165 | #define ICH6_REG_CORBRP 0x4a |
166 | #define ICH6_CORBRP_RST (1 << 15) /* read pointer reset */ | ||
154 | #define ICH6_REG_CORBCTL 0x4c | 167 | #define ICH6_REG_CORBCTL 0x4c |
168 | #define ICH6_CORBCTL_RUN (1 << 1) /* enable DMA */ | ||
169 | #define ICH6_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */ | ||
155 | #define ICH6_REG_CORBSTS 0x4d | 170 | #define ICH6_REG_CORBSTS 0x4d |
171 | #define ICH6_CORBSTS_CMEI (1 << 0) /* memory error indication */ | ||
156 | #define ICH6_REG_CORBSIZE 0x4e | 172 | #define ICH6_REG_CORBSIZE 0x4e |
157 | 173 | ||
158 | #define ICH6_REG_RIRBLBASE 0x50 | 174 | #define ICH6_REG_RIRBLBASE 0x50 |
159 | #define ICH6_REG_RIRBUBASE 0x54 | 175 | #define ICH6_REG_RIRBUBASE 0x54 |
160 | #define ICH6_REG_RIRBWP 0x58 | 176 | #define ICH6_REG_RIRBWP 0x58 |
177 | #define ICH6_RIRBWP_RST (1 << 15) /* write pointer reset */ | ||
161 | #define ICH6_REG_RINTCNT 0x5a | 178 | #define ICH6_REG_RINTCNT 0x5a |
162 | #define ICH6_REG_RIRBCTL 0x5c | 179 | #define ICH6_REG_RIRBCTL 0x5c |
180 | #define ICH6_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */ | ||
181 | #define ICH6_RBCTL_DMA_EN (1 << 1) /* enable DMA */ | ||
182 | #define ICH6_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */ | ||
163 | #define ICH6_REG_RIRBSTS 0x5d | 183 | #define ICH6_REG_RIRBSTS 0x5d |
184 | #define ICH6_RBSTS_IRQ (1 << 0) /* response irq */ | ||
185 | #define ICH6_RBSTS_OVERRUN (1 << 2) /* overrun irq */ | ||
164 | #define ICH6_REG_RIRBSIZE 0x5e | 186 | #define ICH6_REG_RIRBSIZE 0x5e |
165 | 187 | ||
166 | #define ICH6_REG_IC 0x60 | 188 | #define ICH6_REG_IC 0x60 |
@@ -257,16 +279,6 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 }; | |||
257 | #define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ | 279 | #define ICH6_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */ |
258 | #define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ | 280 | #define ICH6_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */ |
259 | 281 | ||
260 | /* GCTL unsolicited response enable bit */ | ||
261 | #define ICH6_GCTL_UREN (1<<8) | ||
262 | |||
263 | /* GCTL reset bit */ | ||
264 | #define ICH6_GCTL_RESET (1<<0) | ||
265 | |||
266 | /* CORB/RIRB control, read/write pointer */ | ||
267 | #define ICH6_RBCTL_DMA_EN 0x02 /* enable DMA */ | ||
268 | #define ICH6_RBCTL_IRQ_EN 0x01 /* enable IRQ */ | ||
269 | #define ICH6_RBRWP_CLR 0x8000 /* read/write pointer clear */ | ||
270 | /* below are so far hardcoded - should read registers in future */ | 282 | /* below are so far hardcoded - should read registers in future */ |
271 | #define ICH6_MAX_CORB_ENTRIES 256 | 283 | #define ICH6_MAX_CORB_ENTRIES 256 |
272 | #define ICH6_MAX_RIRB_ENTRIES 256 | 284 | #define ICH6_MAX_RIRB_ENTRIES 256 |
@@ -512,25 +524,25 @@ static void azx_init_cmd_io(struct azx *chip) | |||
512 | /* set the corb write pointer to 0 */ | 524 | /* set the corb write pointer to 0 */ |
513 | azx_writew(chip, CORBWP, 0); | 525 | azx_writew(chip, CORBWP, 0); |
514 | /* reset the corb hw read pointer */ | 526 | /* reset the corb hw read pointer */ |
515 | azx_writew(chip, CORBRP, ICH6_RBRWP_CLR); | 527 | azx_writew(chip, CORBRP, ICH6_CORBRP_RST); |
516 | /* enable corb dma */ | 528 | /* enable corb dma */ |
517 | azx_writeb(chip, CORBCTL, ICH6_RBCTL_DMA_EN); | 529 | azx_writeb(chip, CORBCTL, ICH6_CORBCTL_RUN); |
518 | 530 | ||
519 | /* RIRB set up */ | 531 | /* RIRB set up */ |
520 | chip->rirb.addr = chip->rb.addr + 2048; | 532 | chip->rirb.addr = chip->rb.addr + 2048; |
521 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); | 533 | chip->rirb.buf = (u32 *)(chip->rb.area + 2048); |
534 | chip->rirb.wp = chip->rirb.rp = chip->rirb.cmds = 0; | ||
522 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); | 535 | azx_writel(chip, RIRBLBASE, (u32)chip->rirb.addr); |
523 | azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); | 536 | azx_writel(chip, RIRBUBASE, upper_32_bits(chip->rirb.addr)); |
524 | 537 | ||
525 | /* set the rirb size to 256 entries (ULI requires explicitly) */ | 538 | /* set the rirb size to 256 entries (ULI requires explicitly) */ |
526 | azx_writeb(chip, RIRBSIZE, 0x02); | 539 | azx_writeb(chip, RIRBSIZE, 0x02); |
527 | /* reset the rirb hw write pointer */ | 540 | /* reset the rirb hw write pointer */ |
528 | azx_writew(chip, RIRBWP, ICH6_RBRWP_CLR); | 541 | azx_writew(chip, RIRBWP, ICH6_RIRBWP_RST); |
529 | /* set N=1, get RIRB response interrupt for new entry */ | 542 | /* set N=1, get RIRB response interrupt for new entry */ |
530 | azx_writew(chip, RINTCNT, 1); | 543 | azx_writew(chip, RINTCNT, 1); |
531 | /* enable rirb dma and response irq */ | 544 | /* enable rirb dma and response irq */ |
532 | azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); | 545 | azx_writeb(chip, RIRBCTL, ICH6_RBCTL_DMA_EN | ICH6_RBCTL_IRQ_EN); |
533 | chip->rirb.rp = chip->rirb.cmds = 0; | ||
534 | } | 546 | } |
535 | 547 | ||
536 | static void azx_free_cmd_io(struct azx *chip) | 548 | static void azx_free_cmd_io(struct azx *chip) |
@@ -606,6 +618,7 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
606 | } | 618 | } |
607 | if (!chip->rirb.cmds) { | 619 | if (!chip->rirb.cmds) { |
608 | smp_rmb(); | 620 | smp_rmb(); |
621 | bus->rirb_error = 0; | ||
609 | return chip->rirb.res; /* the last value */ | 622 | return chip->rirb.res; /* the last value */ |
610 | } | 623 | } |
611 | if (time_after(jiffies, timeout)) | 624 | if (time_after(jiffies, timeout)) |
@@ -619,19 +632,21 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
619 | } | 632 | } |
620 | 633 | ||
621 | if (chip->msi) { | 634 | if (chip->msi) { |
622 | snd_printk(KERN_WARNING "hda_intel: No response from codec, " | 635 | snd_printk(KERN_WARNING SFX "No response from codec, " |
623 | "disabling MSI: last cmd=0x%08x\n", chip->last_cmd); | 636 | "disabling MSI: last cmd=0x%08x\n", chip->last_cmd); |
624 | free_irq(chip->irq, chip); | 637 | free_irq(chip->irq, chip); |
625 | chip->irq = -1; | 638 | chip->irq = -1; |
626 | pci_disable_msi(chip->pci); | 639 | pci_disable_msi(chip->pci); |
627 | chip->msi = 0; | 640 | chip->msi = 0; |
628 | if (azx_acquire_irq(chip, 1) < 0) | 641 | if (azx_acquire_irq(chip, 1) < 0) { |
642 | bus->rirb_error = 1; | ||
629 | return -1; | 643 | return -1; |
644 | } | ||
630 | goto again; | 645 | goto again; |
631 | } | 646 | } |
632 | 647 | ||
633 | if (!chip->polling_mode) { | 648 | if (!chip->polling_mode) { |
634 | snd_printk(KERN_WARNING "hda_intel: azx_get_response timeout, " | 649 | snd_printk(KERN_WARNING SFX "azx_get_response timeout, " |
635 | "switching to polling mode: last cmd=0x%08x\n", | 650 | "switching to polling mode: last cmd=0x%08x\n", |
636 | chip->last_cmd); | 651 | chip->last_cmd); |
637 | chip->polling_mode = 1; | 652 | chip->polling_mode = 1; |
@@ -646,14 +661,23 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
646 | return -1; | 661 | return -1; |
647 | } | 662 | } |
648 | 663 | ||
664 | /* a fatal communication error; need either to reset or to fallback | ||
665 | * to the single_cmd mode | ||
666 | */ | ||
667 | bus->rirb_error = 1; | ||
668 | if (bus->allow_bus_reset && !bus->response_reset && !bus->in_reset) { | ||
669 | bus->response_reset = 1; | ||
670 | return -1; /* give a chance to retry */ | ||
671 | } | ||
672 | |||
649 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " | 673 | snd_printk(KERN_ERR "hda_intel: azx_get_response timeout, " |
650 | "switching to single_cmd mode: last cmd=0x%08x\n", | 674 | "switching to single_cmd mode: last cmd=0x%08x\n", |
651 | chip->last_cmd); | 675 | chip->last_cmd); |
652 | chip->rirb.rp = azx_readb(chip, RIRBWP); | ||
653 | chip->rirb.cmds = 0; | ||
654 | /* switch to single_cmd mode */ | ||
655 | chip->single_cmd = 1; | 676 | chip->single_cmd = 1; |
677 | bus->response_reset = 0; | ||
678 | /* re-initialize CORB/RIRB */ | ||
656 | azx_free_cmd_io(chip); | 679 | azx_free_cmd_io(chip); |
680 | azx_init_cmd_io(chip); | ||
657 | return -1; | 681 | return -1; |
658 | } | 682 | } |
659 | 683 | ||
@@ -667,12 +691,34 @@ static unsigned int azx_rirb_get_response(struct hda_bus *bus) | |||
667 | * I left the codes, however, for debugging/testing purposes. | 691 | * I left the codes, however, for debugging/testing purposes. |
668 | */ | 692 | */ |
669 | 693 | ||
694 | /* receive a response */ | ||
695 | static int azx_single_wait_for_response(struct azx *chip) | ||
696 | { | ||
697 | int timeout = 50; | ||
698 | |||
699 | while (timeout--) { | ||
700 | /* check IRV busy bit */ | ||
701 | if (azx_readw(chip, IRS) & ICH6_IRS_VALID) { | ||
702 | /* reuse rirb.res as the response return value */ | ||
703 | chip->rirb.res = azx_readl(chip, IR); | ||
704 | return 0; | ||
705 | } | ||
706 | udelay(1); | ||
707 | } | ||
708 | if (printk_ratelimit()) | ||
709 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", | ||
710 | azx_readw(chip, IRS)); | ||
711 | chip->rirb.res = -1; | ||
712 | return -EIO; | ||
713 | } | ||
714 | |||
670 | /* send a command */ | 715 | /* send a command */ |
671 | static int azx_single_send_cmd(struct hda_bus *bus, u32 val) | 716 | static int azx_single_send_cmd(struct hda_bus *bus, u32 val) |
672 | { | 717 | { |
673 | struct azx *chip = bus->private_data; | 718 | struct azx *chip = bus->private_data; |
674 | int timeout = 50; | 719 | int timeout = 50; |
675 | 720 | ||
721 | bus->rirb_error = 0; | ||
676 | while (timeout--) { | 722 | while (timeout--) { |
677 | /* check ICB busy bit */ | 723 | /* check ICB busy bit */ |
678 | if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { | 724 | if (!((azx_readw(chip, IRS) & ICH6_IRS_BUSY))) { |
@@ -682,7 +728,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) | |||
682 | azx_writel(chip, IC, val); | 728 | azx_writel(chip, IC, val); |
683 | azx_writew(chip, IRS, azx_readw(chip, IRS) | | 729 | azx_writew(chip, IRS, azx_readw(chip, IRS) | |
684 | ICH6_IRS_BUSY); | 730 | ICH6_IRS_BUSY); |
685 | return 0; | 731 | return azx_single_wait_for_response(chip); |
686 | } | 732 | } |
687 | udelay(1); | 733 | udelay(1); |
688 | } | 734 | } |
@@ -696,18 +742,7 @@ static int azx_single_send_cmd(struct hda_bus *bus, u32 val) | |||
696 | static unsigned int azx_single_get_response(struct hda_bus *bus) | 742 | static unsigned int azx_single_get_response(struct hda_bus *bus) |
697 | { | 743 | { |
698 | struct azx *chip = bus->private_data; | 744 | struct azx *chip = bus->private_data; |
699 | int timeout = 50; | 745 | return chip->rirb.res; |
700 | |||
701 | while (timeout--) { | ||
702 | /* check IRV busy bit */ | ||
703 | if (azx_readw(chip, IRS) & ICH6_IRS_VALID) | ||
704 | return azx_readl(chip, IR); | ||
705 | udelay(1); | ||
706 | } | ||
707 | if (printk_ratelimit()) | ||
708 | snd_printd(SFX "get_response timeout: IRS=0x%x\n", | ||
709 | azx_readw(chip, IRS)); | ||
710 | return (unsigned int)-1; | ||
711 | } | 746 | } |
712 | 747 | ||
713 | /* | 748 | /* |
@@ -775,17 +810,17 @@ static int azx_reset(struct azx *chip) | |||
775 | 810 | ||
776 | /* check to see if controller is ready */ | 811 | /* check to see if controller is ready */ |
777 | if (!azx_readb(chip, GCTL)) { | 812 | if (!azx_readb(chip, GCTL)) { |
778 | snd_printd("azx_reset: controller not ready!\n"); | 813 | snd_printd(SFX "azx_reset: controller not ready!\n"); |
779 | return -EBUSY; | 814 | return -EBUSY; |
780 | } | 815 | } |
781 | 816 | ||
782 | /* Accept unsolicited responses */ | 817 | /* Accept unsolicited responses */ |
783 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UREN); | 818 | azx_writel(chip, GCTL, azx_readl(chip, GCTL) | ICH6_GCTL_UNSOL); |
784 | 819 | ||
785 | /* detect codecs */ | 820 | /* detect codecs */ |
786 | if (!chip->codec_mask) { | 821 | if (!chip->codec_mask) { |
787 | chip->codec_mask = azx_readw(chip, STATESTS); | 822 | chip->codec_mask = azx_readw(chip, STATESTS); |
788 | snd_printdd("codec_mask = 0x%x\n", chip->codec_mask); | 823 | snd_printdd(SFX "codec_mask = 0x%x\n", chip->codec_mask); |
789 | } | 824 | } |
790 | 825 | ||
791 | return 0; | 826 | return 0; |
@@ -895,8 +930,7 @@ static void azx_init_chip(struct azx *chip) | |||
895 | azx_int_enable(chip); | 930 | azx_int_enable(chip); |
896 | 931 | ||
897 | /* initialize the codec command I/O */ | 932 | /* initialize the codec command I/O */ |
898 | if (!chip->single_cmd) | 933 | azx_init_cmd_io(chip); |
899 | azx_init_cmd_io(chip); | ||
900 | 934 | ||
901 | /* program the position buffer */ | 935 | /* program the position buffer */ |
902 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); | 936 | azx_writel(chip, DPLBASE, (u32)chip->posbuf.addr); |
@@ -953,12 +987,12 @@ static void azx_init_pci(struct azx *chip) | |||
953 | case AZX_DRIVER_SCH: | 987 | case AZX_DRIVER_SCH: |
954 | pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); | 988 | pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop); |
955 | if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { | 989 | if (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) { |
956 | pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, \ | 990 | pci_write_config_word(chip->pci, INTEL_SCH_HDA_DEVC, |
957 | snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); | 991 | snoop & (~INTEL_SCH_HDA_DEVC_NOSNOOP)); |
958 | pci_read_config_word(chip->pci, | 992 | pci_read_config_word(chip->pci, |
959 | INTEL_SCH_HDA_DEVC, &snoop); | 993 | INTEL_SCH_HDA_DEVC, &snoop); |
960 | snd_printdd("HDA snoop disabled, enabling ... %s\n",\ | 994 | snd_printdd(SFX "HDA snoop disabled, enabling ... %s\n", |
961 | (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) \ | 995 | (snoop & INTEL_SCH_HDA_DEVC_NOSNOOP) |
962 | ? "Failed" : "OK"); | 996 | ? "Failed" : "OK"); |
963 | } | 997 | } |
964 | break; | 998 | break; |
@@ -1012,7 +1046,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id) | |||
1012 | /* clear rirb int */ | 1046 | /* clear rirb int */ |
1013 | status = azx_readb(chip, RIRBSTS); | 1047 | status = azx_readb(chip, RIRBSTS); |
1014 | if (status & RIRB_INT_MASK) { | 1048 | if (status & RIRB_INT_MASK) { |
1015 | if (!chip->single_cmd && (status & RIRB_INT_RESPONSE)) | 1049 | if (status & RIRB_INT_RESPONSE) |
1016 | azx_update_rirb(chip); | 1050 | azx_update_rirb(chip); |
1017 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); | 1051 | azx_writeb(chip, RIRBSTS, RIRB_INT_MASK); |
1018 | } | 1052 | } |
@@ -1098,7 +1132,7 @@ static int azx_setup_periods(struct azx *chip, | |||
1098 | pos_align; | 1132 | pos_align; |
1099 | pos_adj = frames_to_bytes(runtime, pos_adj); | 1133 | pos_adj = frames_to_bytes(runtime, pos_adj); |
1100 | if (pos_adj >= period_bytes) { | 1134 | if (pos_adj >= period_bytes) { |
1101 | snd_printk(KERN_WARNING "Too big adjustment %d\n", | 1135 | snd_printk(KERN_WARNING SFX "Too big adjustment %d\n", |
1102 | bdl_pos_adj[chip->dev_index]); | 1136 | bdl_pos_adj[chip->dev_index]); |
1103 | pos_adj = 0; | 1137 | pos_adj = 0; |
1104 | } else { | 1138 | } else { |
@@ -1122,7 +1156,7 @@ static int azx_setup_periods(struct azx *chip, | |||
1122 | return 0; | 1156 | return 0; |
1123 | 1157 | ||
1124 | error: | 1158 | error: |
1125 | snd_printk(KERN_ERR "Too many BDL entries: buffer=%d, period=%d\n", | 1159 | snd_printk(KERN_ERR SFX "Too many BDL entries: buffer=%d, period=%d\n", |
1126 | azx_dev->bufsize, period_bytes); | 1160 | azx_dev->bufsize, period_bytes); |
1127 | return -EINVAL; | 1161 | return -EINVAL; |
1128 | } | 1162 | } |
@@ -1215,7 +1249,7 @@ static int probe_codec(struct azx *chip, int addr) | |||
1215 | chip->probing = 0; | 1249 | chip->probing = 0; |
1216 | if (res == -1) | 1250 | if (res == -1) |
1217 | return -EIO; | 1251 | return -EIO; |
1218 | snd_printdd("hda_intel: codec #%d probed OK\n", addr); | 1252 | snd_printdd(SFX "codec #%d probed OK\n", addr); |
1219 | return 0; | 1253 | return 0; |
1220 | } | 1254 | } |
1221 | 1255 | ||
@@ -1223,6 +1257,26 @@ static int azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, | |||
1223 | struct hda_pcm *cpcm); | 1257 | struct hda_pcm *cpcm); |
1224 | static void azx_stop_chip(struct azx *chip); | 1258 | static void azx_stop_chip(struct azx *chip); |
1225 | 1259 | ||
1260 | static void azx_bus_reset(struct hda_bus *bus) | ||
1261 | { | ||
1262 | struct azx *chip = bus->private_data; | ||
1263 | |||
1264 | bus->in_reset = 1; | ||
1265 | azx_stop_chip(chip); | ||
1266 | azx_init_chip(chip); | ||
1267 | #ifdef CONFIG_PM | ||
1268 | if (chip->initialized) { | ||
1269 | int i; | ||
1270 | |||
1271 | for (i = 0; i < AZX_MAX_PCMS; i++) | ||
1272 | snd_pcm_suspend_all(chip->pcm[i]); | ||
1273 | snd_hda_suspend(chip->bus); | ||
1274 | snd_hda_resume(chip->bus); | ||
1275 | } | ||
1276 | #endif | ||
1277 | bus->in_reset = 0; | ||
1278 | } | ||
1279 | |||
1226 | /* | 1280 | /* |
1227 | * Codec initialization | 1281 | * Codec initialization |
1228 | */ | 1282 | */ |
@@ -1246,6 +1300,7 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, | |||
1246 | bus_temp.ops.command = azx_send_cmd; | 1300 | bus_temp.ops.command = azx_send_cmd; |
1247 | bus_temp.ops.get_response = azx_get_response; | 1301 | bus_temp.ops.get_response = azx_get_response; |
1248 | bus_temp.ops.attach_pcm = azx_attach_pcm_stream; | 1302 | bus_temp.ops.attach_pcm = azx_attach_pcm_stream; |
1303 | bus_temp.ops.bus_reset = azx_bus_reset; | ||
1249 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 1304 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
1250 | bus_temp.power_save = &power_save; | 1305 | bus_temp.power_save = &power_save; |
1251 | bus_temp.ops.pm_notify = azx_power_notify; | 1306 | bus_temp.ops.pm_notify = azx_power_notify; |
@@ -1270,8 +1325,8 @@ static int __devinit azx_codec_create(struct azx *chip, const char *model, | |||
1270 | /* Some BIOSen give you wrong codec addresses | 1325 | /* Some BIOSen give you wrong codec addresses |
1271 | * that don't exist | 1326 | * that don't exist |
1272 | */ | 1327 | */ |
1273 | snd_printk(KERN_WARNING | 1328 | snd_printk(KERN_WARNING SFX |
1274 | "hda_intel: Codec #%d probe error; " | 1329 | "Codec #%d probe error; " |
1275 | "disabling it...\n", c); | 1330 | "disabling it...\n", c); |
1276 | chip->codec_mask &= ~(1 << c); | 1331 | chip->codec_mask &= ~(1 << c); |
1277 | /* More badly, accessing to a non-existing | 1332 | /* More badly, accessing to a non-existing |
@@ -1487,7 +1542,7 @@ static int azx_pcm_prepare(struct snd_pcm_substream *substream) | |||
1487 | bufsize = snd_pcm_lib_buffer_bytes(substream); | 1542 | bufsize = snd_pcm_lib_buffer_bytes(substream); |
1488 | period_bytes = snd_pcm_lib_period_bytes(substream); | 1543 | period_bytes = snd_pcm_lib_period_bytes(substream); |
1489 | 1544 | ||
1490 | snd_printdd("azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", | 1545 | snd_printdd(SFX "azx_pcm_prepare: bufsize=0x%x, format=0x%x\n", |
1491 | bufsize, format_val); | 1546 | bufsize, format_val); |
1492 | 1547 | ||
1493 | if (bufsize != azx_dev->bufsize || | 1548 | if (bufsize != azx_dev->bufsize || |
@@ -1830,7 +1885,7 @@ azx_attach_pcm_stream(struct hda_bus *bus, struct hda_codec *codec, | |||
1830 | &pcm); | 1885 | &pcm); |
1831 | if (err < 0) | 1886 | if (err < 0) |
1832 | return err; | 1887 | return err; |
1833 | strcpy(pcm->name, cpcm->name); | 1888 | strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); |
1834 | apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); | 1889 | apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); |
1835 | if (apcm == NULL) | 1890 | if (apcm == NULL) |
1836 | return -ENOMEM; | 1891 | return -ENOMEM; |
@@ -1973,7 +2028,7 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state) | |||
1973 | for (i = 0; i < AZX_MAX_PCMS; i++) | 2028 | for (i = 0; i < AZX_MAX_PCMS; i++) |
1974 | snd_pcm_suspend_all(chip->pcm[i]); | 2029 | snd_pcm_suspend_all(chip->pcm[i]); |
1975 | if (chip->initialized) | 2030 | if (chip->initialized) |
1976 | snd_hda_suspend(chip->bus, state); | 2031 | snd_hda_suspend(chip->bus); |
1977 | azx_stop_chip(chip); | 2032 | azx_stop_chip(chip); |
1978 | if (chip->irq >= 0) { | 2033 | if (chip->irq >= 0) { |
1979 | free_irq(chip->irq, chip); | 2034 | free_irq(chip->irq, chip); |
@@ -2141,6 +2196,7 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { | |||
2141 | /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ | 2196 | /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ |
2142 | SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), | 2197 | SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), |
2143 | /* forced codec slots */ | 2198 | /* forced codec slots */ |
2199 | SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103), | ||
2144 | SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103), | 2200 | SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103), |
2145 | {} | 2201 | {} |
2146 | }; | 2202 | }; |
@@ -2264,14 +2320,14 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
2264 | synchronize_irq(chip->irq); | 2320 | synchronize_irq(chip->irq); |
2265 | 2321 | ||
2266 | gcap = azx_readw(chip, GCAP); | 2322 | gcap = azx_readw(chip, GCAP); |
2267 | snd_printdd("chipset global capabilities = 0x%x\n", gcap); | 2323 | snd_printdd(SFX "chipset global capabilities = 0x%x\n", gcap); |
2268 | 2324 | ||
2269 | /* ATI chips seems buggy about 64bit DMA addresses */ | 2325 | /* ATI chips seems buggy about 64bit DMA addresses */ |
2270 | if (chip->driver_type == AZX_DRIVER_ATI) | 2326 | if (chip->driver_type == AZX_DRIVER_ATI) |
2271 | gcap &= ~0x01; | 2327 | gcap &= ~ICH6_GCAP_64OK; |
2272 | 2328 | ||
2273 | /* allow 64bit DMA address if supported by H/W */ | 2329 | /* allow 64bit DMA address if supported by H/W */ |
2274 | if ((gcap & 0x01) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) | 2330 | if ((gcap & ICH6_GCAP_64OK) && !pci_set_dma_mask(pci, DMA_BIT_MASK(64))) |
2275 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); | 2331 | pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(64)); |
2276 | else { | 2332 | else { |
2277 | pci_set_dma_mask(pci, DMA_BIT_MASK(32)); | 2333 | pci_set_dma_mask(pci, DMA_BIT_MASK(32)); |
@@ -2308,7 +2364,7 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
2308 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), | 2364 | chip->azx_dev = kcalloc(chip->num_streams, sizeof(*chip->azx_dev), |
2309 | GFP_KERNEL); | 2365 | GFP_KERNEL); |
2310 | if (!chip->azx_dev) { | 2366 | if (!chip->azx_dev) { |
2311 | snd_printk(KERN_ERR "cannot malloc azx_dev\n"); | 2367 | snd_printk(KERN_ERR SFX "cannot malloc azx_dev\n"); |
2312 | goto errout; | 2368 | goto errout; |
2313 | } | 2369 | } |
2314 | 2370 | ||
@@ -2331,11 +2387,9 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
2331 | goto errout; | 2387 | goto errout; |
2332 | } | 2388 | } |
2333 | /* allocate CORB/RIRB */ | 2389 | /* allocate CORB/RIRB */ |
2334 | if (!chip->single_cmd) { | 2390 | err = azx_alloc_cmd_io(chip); |
2335 | err = azx_alloc_cmd_io(chip); | 2391 | if (err < 0) |
2336 | if (err < 0) | 2392 | goto errout; |
2337 | goto errout; | ||
2338 | } | ||
2339 | 2393 | ||
2340 | /* initialize streams */ | 2394 | /* initialize streams */ |
2341 | azx_init_stream(chip); | 2395 | azx_init_stream(chip); |
@@ -2358,9 +2412,11 @@ static int __devinit azx_create(struct snd_card *card, struct pci_dev *pci, | |||
2358 | } | 2412 | } |
2359 | 2413 | ||
2360 | strcpy(card->driver, "HDA-Intel"); | 2414 | strcpy(card->driver, "HDA-Intel"); |
2361 | strcpy(card->shortname, driver_short_names[chip->driver_type]); | 2415 | strlcpy(card->shortname, driver_short_names[chip->driver_type], |
2362 | sprintf(card->longname, "%s at 0x%lx irq %i", | 2416 | sizeof(card->shortname)); |
2363 | card->shortname, chip->addr, chip->irq); | 2417 | snprintf(card->longname, sizeof(card->longname), |
2418 | "%s at 0x%lx irq %i", | ||
2419 | card->shortname, chip->addr, chip->irq); | ||
2364 | 2420 | ||
2365 | *rchip = chip; | 2421 | *rchip = chip; |
2366 | return 0; | 2422 | return 0; |
@@ -2513,6 +2569,20 @@ static struct pci_device_id azx_ids[] = { | |||
2513 | { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, | 2569 | { PCI_DEVICE(0x10de, 0x0d97), .driver_data = AZX_DRIVER_NVIDIA }, |
2514 | /* Teradici */ | 2570 | /* Teradici */ |
2515 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, | 2571 | { PCI_DEVICE(0x6549, 0x1200), .driver_data = AZX_DRIVER_TERA }, |
2572 | /* Creative X-Fi (CA0110-IBG) */ | ||
2573 | #if !defined(CONFIG_SND_CTXFI) && !defined(CONFIG_SND_CTXFI_MODULE) | ||
2574 | /* the following entry conflicts with snd-ctxfi driver, | ||
2575 | * as ctxfi driver mutates from HD-audio to native mode with | ||
2576 | * a special command sequence. | ||
2577 | */ | ||
2578 | { PCI_DEVICE(PCI_VENDOR_ID_CREATIVE, PCI_ANY_ID), | ||
2579 | .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, | ||
2580 | .class_mask = 0xffffff, | ||
2581 | .driver_data = AZX_DRIVER_GENERIC }, | ||
2582 | #else | ||
2583 | /* this entry seems still valid -- i.e. without emu20kx chip */ | ||
2584 | { PCI_DEVICE(0x1102, 0x0009), .driver_data = AZX_DRIVER_GENERIC }, | ||
2585 | #endif | ||
2516 | /* AMD Generic, PCI class code and Vendor ID for HD Audio */ | 2586 | /* AMD Generic, PCI class code and Vendor ID for HD Audio */ |
2517 | { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), | 2587 | { PCI_DEVICE(PCI_VENDOR_ID_ATI, PCI_ANY_ID), |
2518 | .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, | 2588 | .class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8, |
diff --git a/sound/pci/hda/hda_proc.c b/sound/pci/hda/hda_proc.c index 93d7499350c6..418c5d1badaa 100644 --- a/sound/pci/hda/hda_proc.c +++ b/sound/pci/hda/hda_proc.c | |||
@@ -466,8 +466,12 @@ static void print_codec_info(struct snd_info_entry *entry, | |||
466 | hda_nid_t nid; | 466 | hda_nid_t nid; |
467 | int i, nodes; | 467 | int i, nodes; |
468 | 468 | ||
469 | snd_iprintf(buffer, "Codec: %s\n", | 469 | snd_iprintf(buffer, "Codec: "); |
470 | codec->name ? codec->name : "Not Set"); | 470 | if (codec->vendor_name && codec->chip_name) |
471 | snd_iprintf(buffer, "%s %s\n", | ||
472 | codec->vendor_name, codec->chip_name); | ||
473 | else | ||
474 | snd_iprintf(buffer, "Not Set\n"); | ||
471 | snd_iprintf(buffer, "Address: %d\n", codec->addr); | 475 | snd_iprintf(buffer, "Address: %d\n", codec->addr); |
472 | snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id); | 476 | snd_iprintf(buffer, "Function Id: 0x%x\n", codec->function_id); |
473 | snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); | 477 | snd_iprintf(buffer, "Vendor Id: 0x%08x\n", codec->vendor_id); |
diff --git a/sound/pci/hda/patch_ca0110.c b/sound/pci/hda/patch_ca0110.c new file mode 100644 index 000000000000..392d108c3558 --- /dev/null +++ b/sound/pci/hda/patch_ca0110.c | |||
@@ -0,0 +1,573 @@ | |||
1 | /* | ||
2 | * HD audio interface patch for Creative X-Fi CA0110-IBG chip | ||
3 | * | ||
4 | * Copyright (c) 2008 Takashi Iwai <tiwai@suse.de> | ||
5 | * | ||
6 | * This driver is free software; you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU General Public License as published by | ||
8 | * the Free Software Foundation; either version 2 of the License, or | ||
9 | * (at your option) any later version. | ||
10 | * | ||
11 | * This driver is distributed in the hope that it will be useful, | ||
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
14 | * GNU General Public License for more details. | ||
15 | * | ||
16 | * You should have received a copy of the GNU General Public License | ||
17 | * along with this program; if not, write to the Free Software | ||
18 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
19 | */ | ||
20 | |||
21 | #include <linux/init.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include <linux/slab.h> | ||
24 | #include <linux/pci.h> | ||
25 | #include <sound/core.h> | ||
26 | #include "hda_codec.h" | ||
27 | #include "hda_local.h" | ||
28 | |||
29 | /* | ||
30 | */ | ||
31 | |||
32 | struct ca0110_spec { | ||
33 | struct auto_pin_cfg autocfg; | ||
34 | struct hda_multi_out multiout; | ||
35 | hda_nid_t out_pins[AUTO_CFG_MAX_OUTS]; | ||
36 | hda_nid_t dacs[AUTO_CFG_MAX_OUTS]; | ||
37 | hda_nid_t hp_dac; | ||
38 | hda_nid_t input_pins[AUTO_PIN_LAST]; | ||
39 | hda_nid_t adcs[AUTO_PIN_LAST]; | ||
40 | hda_nid_t dig_out; | ||
41 | hda_nid_t dig_in; | ||
42 | unsigned int num_inputs; | ||
43 | const char *input_labels[AUTO_PIN_LAST]; | ||
44 | struct hda_pcm pcm_rec[2]; /* PCM information */ | ||
45 | }; | ||
46 | |||
47 | /* | ||
48 | * PCM callbacks | ||
49 | */ | ||
50 | static int ca0110_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
51 | struct hda_codec *codec, | ||
52 | struct snd_pcm_substream *substream) | ||
53 | { | ||
54 | struct ca0110_spec *spec = codec->spec; | ||
55 | return snd_hda_multi_out_analog_open(codec, &spec->multiout, substream, | ||
56 | hinfo); | ||
57 | } | ||
58 | |||
59 | static int ca0110_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
60 | struct hda_codec *codec, | ||
61 | unsigned int stream_tag, | ||
62 | unsigned int format, | ||
63 | struct snd_pcm_substream *substream) | ||
64 | { | ||
65 | struct ca0110_spec *spec = codec->spec; | ||
66 | return snd_hda_multi_out_analog_prepare(codec, &spec->multiout, | ||
67 | stream_tag, format, substream); | ||
68 | } | ||
69 | |||
70 | static int ca0110_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
71 | struct hda_codec *codec, | ||
72 | struct snd_pcm_substream *substream) | ||
73 | { | ||
74 | struct ca0110_spec *spec = codec->spec; | ||
75 | return snd_hda_multi_out_analog_cleanup(codec, &spec->multiout); | ||
76 | } | ||
77 | |||
78 | /* | ||
79 | * Digital out | ||
80 | */ | ||
81 | static int ca0110_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | ||
82 | struct hda_codec *codec, | ||
83 | struct snd_pcm_substream *substream) | ||
84 | { | ||
85 | struct ca0110_spec *spec = codec->spec; | ||
86 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | ||
87 | } | ||
88 | |||
89 | static int ca0110_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | ||
90 | struct hda_codec *codec, | ||
91 | struct snd_pcm_substream *substream) | ||
92 | { | ||
93 | struct ca0110_spec *spec = codec->spec; | ||
94 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
95 | } | ||
96 | |||
97 | static int ca0110_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
98 | struct hda_codec *codec, | ||
99 | unsigned int stream_tag, | ||
100 | unsigned int format, | ||
101 | struct snd_pcm_substream *substream) | ||
102 | { | ||
103 | struct ca0110_spec *spec = codec->spec; | ||
104 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | ||
105 | format, substream); | ||
106 | } | ||
107 | |||
108 | /* | ||
109 | * Analog capture | ||
110 | */ | ||
111 | static int ca0110_capture_pcm_prepare(struct hda_pcm_stream *hinfo, | ||
112 | struct hda_codec *codec, | ||
113 | unsigned int stream_tag, | ||
114 | unsigned int format, | ||
115 | struct snd_pcm_substream *substream) | ||
116 | { | ||
117 | struct ca0110_spec *spec = codec->spec; | ||
118 | |||
119 | snd_hda_codec_setup_stream(codec, spec->adcs[substream->number], | ||
120 | stream_tag, 0, format); | ||
121 | return 0; | ||
122 | } | ||
123 | |||
124 | static int ca0110_capture_pcm_cleanup(struct hda_pcm_stream *hinfo, | ||
125 | struct hda_codec *codec, | ||
126 | struct snd_pcm_substream *substream) | ||
127 | { | ||
128 | struct ca0110_spec *spec = codec->spec; | ||
129 | |||
130 | snd_hda_codec_cleanup_stream(codec, spec->adcs[substream->number]); | ||
131 | return 0; | ||
132 | } | ||
133 | |||
134 | /* | ||
135 | */ | ||
136 | |||
137 | static char *dirstr[2] = { "Playback", "Capture" }; | ||
138 | |||
139 | static int _add_switch(struct hda_codec *codec, hda_nid_t nid, const char *pfx, | ||
140 | int chan, int dir) | ||
141 | { | ||
142 | char namestr[44]; | ||
143 | int type = dir ? HDA_INPUT : HDA_OUTPUT; | ||
144 | struct snd_kcontrol_new knew = | ||
145 | HDA_CODEC_MUTE_MONO(namestr, nid, chan, 0, type); | ||
146 | sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); | ||
147 | return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); | ||
148 | } | ||
149 | |||
150 | static int _add_volume(struct hda_codec *codec, hda_nid_t nid, const char *pfx, | ||
151 | int chan, int dir) | ||
152 | { | ||
153 | char namestr[44]; | ||
154 | int type = dir ? HDA_INPUT : HDA_OUTPUT; | ||
155 | struct snd_kcontrol_new knew = | ||
156 | HDA_CODEC_VOLUME_MONO(namestr, nid, chan, 0, type); | ||
157 | sprintf(namestr, "%s %s Volume", pfx, dirstr[dir]); | ||
158 | return snd_hda_ctl_add(codec, snd_ctl_new1(&knew, codec)); | ||
159 | } | ||
160 | |||
161 | #define add_out_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 0) | ||
162 | #define add_out_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 0) | ||
163 | #define add_in_switch(codec, nid, pfx) _add_switch(codec, nid, pfx, 3, 1) | ||
164 | #define add_in_volume(codec, nid, pfx) _add_volume(codec, nid, pfx, 3, 1) | ||
165 | #define add_mono_switch(codec, nid, pfx, chan) \ | ||
166 | _add_switch(codec, nid, pfx, chan, 0) | ||
167 | #define add_mono_volume(codec, nid, pfx, chan) \ | ||
168 | _add_volume(codec, nid, pfx, chan, 0) | ||
169 | |||
170 | static int ca0110_build_controls(struct hda_codec *codec) | ||
171 | { | ||
172 | struct ca0110_spec *spec = codec->spec; | ||
173 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
174 | static char *prefix[AUTO_CFG_MAX_OUTS] = { | ||
175 | "Front", "Surround", NULL, "Side", "Multi" | ||
176 | }; | ||
177 | hda_nid_t mutenid; | ||
178 | int i, err; | ||
179 | |||
180 | for (i = 0; i < spec->multiout.num_dacs; i++) { | ||
181 | if (get_wcaps(codec, spec->out_pins[i]) & AC_WCAP_OUT_AMP) | ||
182 | mutenid = spec->out_pins[i]; | ||
183 | else | ||
184 | mutenid = spec->multiout.dac_nids[i]; | ||
185 | if (!prefix[i]) { | ||
186 | err = add_mono_switch(codec, mutenid, | ||
187 | "Center", 1); | ||
188 | if (err < 0) | ||
189 | return err; | ||
190 | err = add_mono_switch(codec, mutenid, | ||
191 | "LFE", 1); | ||
192 | if (err < 0) | ||
193 | return err; | ||
194 | err = add_mono_volume(codec, spec->multiout.dac_nids[i], | ||
195 | "Center", 1); | ||
196 | if (err < 0) | ||
197 | return err; | ||
198 | err = add_mono_volume(codec, spec->multiout.dac_nids[i], | ||
199 | "LFE", 1); | ||
200 | if (err < 0) | ||
201 | return err; | ||
202 | } else { | ||
203 | err = add_out_switch(codec, mutenid, | ||
204 | prefix[i]); | ||
205 | if (err < 0) | ||
206 | return err; | ||
207 | err = add_out_volume(codec, spec->multiout.dac_nids[i], | ||
208 | prefix[i]); | ||
209 | if (err < 0) | ||
210 | return err; | ||
211 | } | ||
212 | } | ||
213 | if (cfg->hp_outs) { | ||
214 | if (get_wcaps(codec, cfg->hp_pins[0]) & AC_WCAP_OUT_AMP) | ||
215 | mutenid = cfg->hp_pins[0]; | ||
216 | else | ||
217 | mutenid = spec->multiout.dac_nids[i]; | ||
218 | |||
219 | err = add_out_switch(codec, mutenid, "Headphone"); | ||
220 | if (err < 0) | ||
221 | return err; | ||
222 | if (spec->hp_dac) { | ||
223 | err = add_out_volume(codec, spec->hp_dac, "Headphone"); | ||
224 | if (err < 0) | ||
225 | return err; | ||
226 | } | ||
227 | } | ||
228 | for (i = 0; i < spec->num_inputs; i++) { | ||
229 | const char *label = spec->input_labels[i]; | ||
230 | if (get_wcaps(codec, spec->input_pins[i]) & AC_WCAP_IN_AMP) | ||
231 | mutenid = spec->input_pins[i]; | ||
232 | else | ||
233 | mutenid = spec->adcs[i]; | ||
234 | err = add_in_switch(codec, mutenid, label); | ||
235 | if (err < 0) | ||
236 | return err; | ||
237 | err = add_in_volume(codec, spec->adcs[i], label); | ||
238 | if (err < 0) | ||
239 | return err; | ||
240 | } | ||
241 | |||
242 | if (spec->dig_out) { | ||
243 | err = snd_hda_create_spdif_out_ctls(codec, spec->dig_out); | ||
244 | if (err < 0) | ||
245 | return err; | ||
246 | err = snd_hda_create_spdif_share_sw(codec, &spec->multiout); | ||
247 | if (err < 0) | ||
248 | return err; | ||
249 | spec->multiout.share_spdif = 1; | ||
250 | } | ||
251 | if (spec->dig_in) { | ||
252 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in); | ||
253 | if (err < 0) | ||
254 | return err; | ||
255 | err = add_in_volume(codec, spec->dig_in, "IEC958"); | ||
256 | } | ||
257 | return 0; | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | */ | ||
262 | static struct hda_pcm_stream ca0110_pcm_analog_playback = { | ||
263 | .substreams = 1, | ||
264 | .channels_min = 2, | ||
265 | .channels_max = 8, | ||
266 | .ops = { | ||
267 | .open = ca0110_playback_pcm_open, | ||
268 | .prepare = ca0110_playback_pcm_prepare, | ||
269 | .cleanup = ca0110_playback_pcm_cleanup | ||
270 | }, | ||
271 | }; | ||
272 | |||
273 | static struct hda_pcm_stream ca0110_pcm_analog_capture = { | ||
274 | .substreams = 1, | ||
275 | .channels_min = 2, | ||
276 | .channels_max = 2, | ||
277 | .ops = { | ||
278 | .prepare = ca0110_capture_pcm_prepare, | ||
279 | .cleanup = ca0110_capture_pcm_cleanup | ||
280 | }, | ||
281 | }; | ||
282 | |||
283 | static struct hda_pcm_stream ca0110_pcm_digital_playback = { | ||
284 | .substreams = 1, | ||
285 | .channels_min = 2, | ||
286 | .channels_max = 2, | ||
287 | .ops = { | ||
288 | .open = ca0110_dig_playback_pcm_open, | ||
289 | .close = ca0110_dig_playback_pcm_close, | ||
290 | .prepare = ca0110_dig_playback_pcm_prepare | ||
291 | }, | ||
292 | }; | ||
293 | |||
294 | static struct hda_pcm_stream ca0110_pcm_digital_capture = { | ||
295 | .substreams = 1, | ||
296 | .channels_min = 2, | ||
297 | .channels_max = 2, | ||
298 | }; | ||
299 | |||
300 | static int ca0110_build_pcms(struct hda_codec *codec) | ||
301 | { | ||
302 | struct ca0110_spec *spec = codec->spec; | ||
303 | struct hda_pcm *info = spec->pcm_rec; | ||
304 | |||
305 | codec->pcm_info = info; | ||
306 | codec->num_pcms = 0; | ||
307 | |||
308 | info->name = "CA0110 Analog"; | ||
309 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0110_pcm_analog_playback; | ||
310 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; | ||
311 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = | ||
312 | spec->multiout.max_channels; | ||
313 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0110_pcm_analog_capture; | ||
314 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = spec->num_inputs; | ||
315 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; | ||
316 | codec->num_pcms++; | ||
317 | |||
318 | if (!spec->dig_out && !spec->dig_in) | ||
319 | return 0; | ||
320 | |||
321 | info++; | ||
322 | info->name = "CA0110 Digital"; | ||
323 | info->pcm_type = HDA_PCM_TYPE_SPDIF; | ||
324 | if (spec->dig_out) { | ||
325 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = | ||
326 | ca0110_pcm_digital_playback; | ||
327 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dig_out; | ||
328 | } | ||
329 | if (spec->dig_in) { | ||
330 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = | ||
331 | ca0110_pcm_digital_capture; | ||
332 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->dig_in; | ||
333 | } | ||
334 | codec->num_pcms++; | ||
335 | |||
336 | return 0; | ||
337 | } | ||
338 | |||
339 | static void init_output(struct hda_codec *codec, hda_nid_t pin, hda_nid_t dac) | ||
340 | { | ||
341 | if (pin) { | ||
342 | snd_hda_codec_write(codec, pin, 0, | ||
343 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); | ||
344 | if (get_wcaps(codec, pin) & AC_WCAP_OUT_AMP) | ||
345 | snd_hda_codec_write(codec, pin, 0, | ||
346 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
347 | AMP_OUT_UNMUTE); | ||
348 | } | ||
349 | if (dac) | ||
350 | snd_hda_codec_write(codec, dac, 0, | ||
351 | AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO); | ||
352 | } | ||
353 | |||
354 | static void init_input(struct hda_codec *codec, hda_nid_t pin, hda_nid_t adc) | ||
355 | { | ||
356 | if (pin) { | ||
357 | snd_hda_codec_write(codec, pin, 0, | ||
358 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80); | ||
359 | if (get_wcaps(codec, pin) & AC_WCAP_IN_AMP) | ||
360 | snd_hda_codec_write(codec, pin, 0, | ||
361 | AC_VERB_SET_AMP_GAIN_MUTE, | ||
362 | AMP_IN_UNMUTE(0)); | ||
363 | } | ||
364 | if (adc) | ||
365 | snd_hda_codec_write(codec, adc, 0, AC_VERB_SET_AMP_GAIN_MUTE, | ||
366 | AMP_IN_UNMUTE(0)); | ||
367 | } | ||
368 | |||
369 | static int ca0110_init(struct hda_codec *codec) | ||
370 | { | ||
371 | struct ca0110_spec *spec = codec->spec; | ||
372 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
373 | int i; | ||
374 | |||
375 | for (i = 0; i < spec->multiout.num_dacs; i++) | ||
376 | init_output(codec, spec->out_pins[i], | ||
377 | spec->multiout.dac_nids[i]); | ||
378 | init_output(codec, cfg->hp_pins[0], spec->hp_dac); | ||
379 | init_output(codec, cfg->dig_out_pins[0], spec->dig_out); | ||
380 | |||
381 | for (i = 0; i < spec->num_inputs; i++) | ||
382 | init_input(codec, spec->input_pins[i], spec->adcs[i]); | ||
383 | init_input(codec, cfg->dig_in_pin, spec->dig_in); | ||
384 | return 0; | ||
385 | } | ||
386 | |||
387 | static void ca0110_free(struct hda_codec *codec) | ||
388 | { | ||
389 | kfree(codec->spec); | ||
390 | } | ||
391 | |||
392 | static struct hda_codec_ops ca0110_patch_ops = { | ||
393 | .build_controls = ca0110_build_controls, | ||
394 | .build_pcms = ca0110_build_pcms, | ||
395 | .init = ca0110_init, | ||
396 | .free = ca0110_free, | ||
397 | }; | ||
398 | |||
399 | |||
400 | static void parse_line_outs(struct hda_codec *codec) | ||
401 | { | ||
402 | struct ca0110_spec *spec = codec->spec; | ||
403 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
404 | int i, n; | ||
405 | unsigned int def_conf; | ||
406 | hda_nid_t nid; | ||
407 | |||
408 | n = 0; | ||
409 | for (i = 0; i < cfg->line_outs; i++) { | ||
410 | nid = cfg->line_out_pins[i]; | ||
411 | def_conf = snd_hda_codec_get_pincfg(codec, nid); | ||
412 | if (!def_conf) | ||
413 | continue; /* invalid pin */ | ||
414 | if (snd_hda_get_connections(codec, nid, &spec->dacs[i], 1) != 1) | ||
415 | continue; | ||
416 | spec->out_pins[n++] = nid; | ||
417 | } | ||
418 | spec->multiout.dac_nids = spec->dacs; | ||
419 | spec->multiout.num_dacs = n; | ||
420 | spec->multiout.max_channels = n * 2; | ||
421 | } | ||
422 | |||
423 | static void parse_hp_out(struct hda_codec *codec) | ||
424 | { | ||
425 | struct ca0110_spec *spec = codec->spec; | ||
426 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
427 | int i; | ||
428 | unsigned int def_conf; | ||
429 | hda_nid_t nid, dac; | ||
430 | |||
431 | if (!cfg->hp_outs) | ||
432 | return; | ||
433 | nid = cfg->hp_pins[0]; | ||
434 | def_conf = snd_hda_codec_get_pincfg(codec, nid); | ||
435 | if (!def_conf) { | ||
436 | cfg->hp_outs = 0; | ||
437 | return; | ||
438 | } | ||
439 | if (snd_hda_get_connections(codec, nid, &dac, 1) != 1) | ||
440 | return; | ||
441 | |||
442 | for (i = 0; i < cfg->line_outs; i++) | ||
443 | if (dac == spec->dacs[i]) | ||
444 | break; | ||
445 | if (i >= cfg->line_outs) { | ||
446 | spec->hp_dac = dac; | ||
447 | spec->multiout.hp_nid = dac; | ||
448 | } | ||
449 | } | ||
450 | |||
451 | static void parse_input(struct hda_codec *codec) | ||
452 | { | ||
453 | struct ca0110_spec *spec = codec->spec; | ||
454 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
455 | hda_nid_t nid, pin; | ||
456 | int n, i, j; | ||
457 | |||
458 | n = 0; | ||
459 | nid = codec->start_nid; | ||
460 | for (i = 0; i < codec->num_nodes; i++, nid++) { | ||
461 | unsigned int wcaps = get_wcaps(codec, nid); | ||
462 | unsigned int type = (wcaps & AC_WCAP_TYPE) >> | ||
463 | AC_WCAP_TYPE_SHIFT; | ||
464 | if (type != AC_WID_AUD_IN) | ||
465 | continue; | ||
466 | if (snd_hda_get_connections(codec, nid, &pin, 1) != 1) | ||
467 | continue; | ||
468 | if (pin == cfg->dig_in_pin) { | ||
469 | spec->dig_in = nid; | ||
470 | continue; | ||
471 | } | ||
472 | for (j = 0; j < AUTO_PIN_LAST; j++) | ||
473 | if (cfg->input_pins[j] == pin) | ||
474 | break; | ||
475 | if (j >= AUTO_PIN_LAST) | ||
476 | continue; | ||
477 | spec->input_pins[n] = pin; | ||
478 | spec->input_labels[n] = auto_pin_cfg_labels[j]; | ||
479 | spec->adcs[n] = nid; | ||
480 | n++; | ||
481 | } | ||
482 | spec->num_inputs = n; | ||
483 | } | ||
484 | |||
485 | static void parse_digital(struct hda_codec *codec) | ||
486 | { | ||
487 | struct ca0110_spec *spec = codec->spec; | ||
488 | struct auto_pin_cfg *cfg = &spec->autocfg; | ||
489 | |||
490 | if (cfg->dig_outs && | ||
491 | snd_hda_get_connections(codec, cfg->dig_out_pins[0], | ||
492 | &spec->dig_out, 1) == 1) | ||
493 | spec->multiout.dig_out_nid = cfg->dig_out_pins[0]; | ||
494 | } | ||
495 | |||
496 | static int ca0110_parse_auto_config(struct hda_codec *codec) | ||
497 | { | ||
498 | struct ca0110_spec *spec = codec->spec; | ||
499 | int err; | ||
500 | |||
501 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); | ||
502 | if (err < 0) | ||
503 | return err; | ||
504 | |||
505 | parse_line_outs(codec); | ||
506 | parse_hp_out(codec); | ||
507 | parse_digital(codec); | ||
508 | parse_input(codec); | ||
509 | return 0; | ||
510 | } | ||
511 | |||
512 | |||
513 | int patch_ca0110(struct hda_codec *codec) | ||
514 | { | ||
515 | struct ca0110_spec *spec; | ||
516 | int err; | ||
517 | |||
518 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
519 | if (!spec) | ||
520 | return -ENOMEM; | ||
521 | codec->spec = spec; | ||
522 | |||
523 | codec->bus->needs_damn_long_delay = 1; | ||
524 | |||
525 | err = ca0110_parse_auto_config(codec); | ||
526 | if (err < 0) | ||
527 | goto error; | ||
528 | |||
529 | codec->patch_ops = ca0110_patch_ops; | ||
530 | |||
531 | return 0; | ||
532 | |||
533 | error: | ||
534 | kfree(codec->spec); | ||
535 | codec->spec = NULL; | ||
536 | return err; | ||
537 | } | ||
538 | |||
539 | |||
540 | /* | ||
541 | * patch entries | ||
542 | */ | ||
543 | static struct hda_codec_preset snd_hda_preset_ca0110[] = { | ||
544 | { .id = 0x1102000a, .name = "CA0110-IBG", .patch = patch_ca0110 }, | ||
545 | { .id = 0x1102000b, .name = "CA0110-IBG", .patch = patch_ca0110 }, | ||
546 | { .id = 0x1102000d, .name = "SB0880 X-Fi", .patch = patch_ca0110 }, | ||
547 | {} /* terminator */ | ||
548 | }; | ||
549 | |||
550 | MODULE_ALIAS("snd-hda-codec-id:1102000a"); | ||
551 | MODULE_ALIAS("snd-hda-codec-id:1102000b"); | ||
552 | MODULE_ALIAS("snd-hda-codec-id:1102000d"); | ||
553 | |||
554 | MODULE_LICENSE("GPL"); | ||
555 | MODULE_DESCRIPTION("Creative CA0110-IBG HD-audio codec"); | ||
556 | |||
557 | static struct hda_codec_preset_list ca0110_list = { | ||
558 | .preset = snd_hda_preset_ca0110, | ||
559 | .owner = THIS_MODULE, | ||
560 | }; | ||
561 | |||
562 | static int __init patch_ca0110_init(void) | ||
563 | { | ||
564 | return snd_hda_add_codec_preset(&ca0110_list); | ||
565 | } | ||
566 | |||
567 | static void __exit patch_ca0110_exit(void) | ||
568 | { | ||
569 | snd_hda_delete_codec_preset(&ca0110_list); | ||
570 | } | ||
571 | |||
572 | module_init(patch_ca0110_init) | ||
573 | module_exit(patch_ca0110_exit) | ||
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 56ce19e68cb5..4fcbe21829ab 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -1848,6 +1848,7 @@ static const char *cxt5051_models[CXT5051_MODELS] = { | |||
1848 | 1848 | ||
1849 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { | 1849 | static struct snd_pci_quirk cxt5051_cfg_tbl[] = { |
1850 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), | 1850 | SND_PCI_QUIRK(0x103c, 0x30cf, "HP DV6736", CXT5051_HP_DV6736), |
1851 | SND_PCI_QUIRK(0x103c, 0x360b, "Compaq Presario CQ60", CXT5051_HP), | ||
1851 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", | 1852 | SND_PCI_QUIRK(0x14f1, 0x0101, "Conexant Reference board", |
1852 | CXT5051_LAPTOP), | 1853 | CXT5051_LAPTOP), |
1853 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), | 1854 | SND_PCI_QUIRK(0x14f1, 0x5051, "HP Spartan 1.1", CXT5051_HP), |
diff --git a/sound/pci/hda/patch_nvhdmi.c b/sound/pci/hda/patch_nvhdmi.c index d57d8132a06e..f5792e2eea82 100644 --- a/sound/pci/hda/patch_nvhdmi.c +++ b/sound/pci/hda/patch_nvhdmi.c | |||
@@ -35,9 +35,28 @@ struct nvhdmi_spec { | |||
35 | struct hda_pcm pcm_rec; | 35 | struct hda_pcm pcm_rec; |
36 | }; | 36 | }; |
37 | 37 | ||
38 | #define Nv_VERB_SET_Channel_Allocation 0xF79 | ||
39 | #define Nv_VERB_SET_Info_Frame_Checksum 0xF7A | ||
40 | #define Nv_VERB_SET_Audio_Protection_On 0xF98 | ||
41 | #define Nv_VERB_SET_Audio_Protection_Off 0xF99 | ||
42 | |||
43 | #define Nv_Master_Convert_nid 0x04 | ||
44 | #define Nv_Master_Pin_nid 0x05 | ||
45 | |||
46 | static hda_nid_t nvhdmi_convert_nids[4] = { | ||
47 | /*front, rear, clfe, rear_surr */ | ||
48 | 0x6, 0x8, 0xa, 0xc, | ||
49 | }; | ||
50 | |||
38 | static struct hda_verb nvhdmi_basic_init[] = { | 51 | static struct hda_verb nvhdmi_basic_init[] = { |
52 | /* set audio protect on */ | ||
53 | { 0x1, Nv_VERB_SET_Audio_Protection_On, 0x1}, | ||
39 | /* enable digital output on pin widget */ | 54 | /* enable digital output on pin widget */ |
40 | { 0x05, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | 55 | { 0x5, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, |
56 | { 0x7, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, | ||
57 | { 0x9, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, | ||
58 | { 0xb, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, | ||
59 | { 0xd, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x5 }, | ||
41 | {} /* terminator */ | 60 | {} /* terminator */ |
42 | }; | 61 | }; |
43 | 62 | ||
@@ -66,48 +85,205 @@ static int nvhdmi_init(struct hda_codec *codec) | |||
66 | * Digital out | 85 | * Digital out |
67 | */ | 86 | */ |
68 | static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, | 87 | static int nvhdmi_dig_playback_pcm_open(struct hda_pcm_stream *hinfo, |
69 | struct hda_codec *codec, | 88 | struct hda_codec *codec, |
70 | struct snd_pcm_substream *substream) | 89 | struct snd_pcm_substream *substream) |
71 | { | 90 | { |
72 | struct nvhdmi_spec *spec = codec->spec; | 91 | struct nvhdmi_spec *spec = codec->spec; |
73 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); | 92 | return snd_hda_multi_out_dig_open(codec, &spec->multiout); |
74 | } | 93 | } |
75 | 94 | ||
76 | static int nvhdmi_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | 95 | static int nvhdmi_dig_playback_pcm_close_8ch(struct hda_pcm_stream *hinfo, |
77 | struct hda_codec *codec, | 96 | struct hda_codec *codec, |
78 | struct snd_pcm_substream *substream) | 97 | struct snd_pcm_substream *substream) |
79 | { | 98 | { |
80 | struct nvhdmi_spec *spec = codec->spec; | 99 | struct nvhdmi_spec *spec = codec->spec; |
100 | int i; | ||
101 | |||
102 | snd_hda_codec_write(codec, Nv_Master_Convert_nid, | ||
103 | 0, AC_VERB_SET_CHANNEL_STREAMID, 0); | ||
104 | for (i = 0; i < 4; i++) { | ||
105 | /* set the stream id */ | ||
106 | snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, | ||
107 | AC_VERB_SET_CHANNEL_STREAMID, 0); | ||
108 | /* set the stream format */ | ||
109 | snd_hda_codec_write(codec, nvhdmi_convert_nids[i], 0, | ||
110 | AC_VERB_SET_STREAM_FORMAT, 0); | ||
111 | } | ||
112 | |||
81 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | 113 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); |
82 | } | 114 | } |
83 | 115 | ||
84 | static int nvhdmi_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 116 | static int nvhdmi_dig_playback_pcm_close_2ch(struct hda_pcm_stream *hinfo, |
85 | struct hda_codec *codec, | 117 | struct hda_codec *codec, |
86 | unsigned int stream_tag, | 118 | struct snd_pcm_substream *substream) |
87 | unsigned int format, | 119 | { |
88 | struct snd_pcm_substream *substream) | 120 | struct nvhdmi_spec *spec = codec->spec; |
121 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | ||
122 | } | ||
123 | |||
124 | static int nvhdmi_dig_playback_pcm_prepare_8ch(struct hda_pcm_stream *hinfo, | ||
125 | struct hda_codec *codec, | ||
126 | unsigned int stream_tag, | ||
127 | unsigned int format, | ||
128 | struct snd_pcm_substream *substream) | ||
129 | { | ||
130 | int chs; | ||
131 | unsigned int dataDCC1, dataDCC2, chan, chanmask, channel_id; | ||
132 | int i; | ||
133 | |||
134 | mutex_lock(&codec->spdif_mutex); | ||
135 | |||
136 | chs = substream->runtime->channels; | ||
137 | chan = chs ? (chs - 1) : 1; | ||
138 | |||
139 | switch (chs) { | ||
140 | default: | ||
141 | case 0: | ||
142 | case 2: | ||
143 | chanmask = 0x00; | ||
144 | break; | ||
145 | case 4: | ||
146 | chanmask = 0x08; | ||
147 | break; | ||
148 | case 6: | ||
149 | chanmask = 0x0b; | ||
150 | break; | ||
151 | case 8: | ||
152 | chanmask = 0x13; | ||
153 | break; | ||
154 | } | ||
155 | dataDCC1 = AC_DIG1_ENABLE | AC_DIG1_COPYRIGHT; | ||
156 | dataDCC2 = 0x2; | ||
157 | |||
158 | /* set the Audio InforFrame Channel Allocation */ | ||
159 | snd_hda_codec_write(codec, 0x1, 0, | ||
160 | Nv_VERB_SET_Channel_Allocation, chanmask); | ||
161 | |||
162 | /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ | ||
163 | if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) | ||
164 | snd_hda_codec_write(codec, | ||
165 | Nv_Master_Convert_nid, | ||
166 | 0, | ||
167 | AC_VERB_SET_DIGI_CONVERT_1, | ||
168 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | ||
169 | |||
170 | /* set the stream id */ | ||
171 | snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, | ||
172 | AC_VERB_SET_CHANNEL_STREAMID, (stream_tag << 4) | 0x0); | ||
173 | |||
174 | /* set the stream format */ | ||
175 | snd_hda_codec_write(codec, Nv_Master_Convert_nid, 0, | ||
176 | AC_VERB_SET_STREAM_FORMAT, format); | ||
177 | |||
178 | /* turn on again (if needed) */ | ||
179 | /* enable and set the channel status audio/data flag */ | ||
180 | if (codec->spdif_status_reset && (codec->spdif_ctls & AC_DIG1_ENABLE)) { | ||
181 | snd_hda_codec_write(codec, | ||
182 | Nv_Master_Convert_nid, | ||
183 | 0, | ||
184 | AC_VERB_SET_DIGI_CONVERT_1, | ||
185 | codec->spdif_ctls & 0xff); | ||
186 | snd_hda_codec_write(codec, | ||
187 | Nv_Master_Convert_nid, | ||
188 | 0, | ||
189 | AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); | ||
190 | } | ||
191 | |||
192 | for (i = 0; i < 4; i++) { | ||
193 | if (chs == 2) | ||
194 | channel_id = 0; | ||
195 | else | ||
196 | channel_id = i * 2; | ||
197 | |||
198 | /* turn off SPDIF once; | ||
199 | *otherwise the IEC958 bits won't be updated | ||
200 | */ | ||
201 | if (codec->spdif_status_reset && | ||
202 | (codec->spdif_ctls & AC_DIG1_ENABLE)) | ||
203 | snd_hda_codec_write(codec, | ||
204 | nvhdmi_convert_nids[i], | ||
205 | 0, | ||
206 | AC_VERB_SET_DIGI_CONVERT_1, | ||
207 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | ||
208 | /* set the stream id */ | ||
209 | snd_hda_codec_write(codec, | ||
210 | nvhdmi_convert_nids[i], | ||
211 | 0, | ||
212 | AC_VERB_SET_CHANNEL_STREAMID, | ||
213 | (stream_tag << 4) | channel_id); | ||
214 | /* set the stream format */ | ||
215 | snd_hda_codec_write(codec, | ||
216 | nvhdmi_convert_nids[i], | ||
217 | 0, | ||
218 | AC_VERB_SET_STREAM_FORMAT, | ||
219 | format); | ||
220 | /* turn on again (if needed) */ | ||
221 | /* enable and set the channel status audio/data flag */ | ||
222 | if (codec->spdif_status_reset && | ||
223 | (codec->spdif_ctls & AC_DIG1_ENABLE)) { | ||
224 | snd_hda_codec_write(codec, | ||
225 | nvhdmi_convert_nids[i], | ||
226 | 0, | ||
227 | AC_VERB_SET_DIGI_CONVERT_1, | ||
228 | codec->spdif_ctls & 0xff); | ||
229 | snd_hda_codec_write(codec, | ||
230 | nvhdmi_convert_nids[i], | ||
231 | 0, | ||
232 | AC_VERB_SET_DIGI_CONVERT_2, dataDCC2); | ||
233 | } | ||
234 | } | ||
235 | |||
236 | /* set the Audio Info Frame Checksum */ | ||
237 | snd_hda_codec_write(codec, 0x1, 0, | ||
238 | Nv_VERB_SET_Info_Frame_Checksum, | ||
239 | (0x71 - chan - chanmask)); | ||
240 | |||
241 | mutex_unlock(&codec->spdif_mutex); | ||
242 | return 0; | ||
243 | } | ||
244 | |||
245 | static int nvhdmi_dig_playback_pcm_prepare_2ch(struct hda_pcm_stream *hinfo, | ||
246 | struct hda_codec *codec, | ||
247 | unsigned int stream_tag, | ||
248 | unsigned int format, | ||
249 | struct snd_pcm_substream *substream) | ||
89 | { | 250 | { |
90 | struct nvhdmi_spec *spec = codec->spec; | 251 | struct nvhdmi_spec *spec = codec->spec; |
91 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, | 252 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, stream_tag, |
92 | format, substream); | 253 | format, substream); |
93 | } | 254 | } |
94 | 255 | ||
95 | static struct hda_pcm_stream nvhdmi_pcm_digital_playback = { | 256 | static struct hda_pcm_stream nvhdmi_pcm_digital_playback_8ch = { |
257 | .substreams = 1, | ||
258 | .channels_min = 2, | ||
259 | .channels_max = 8, | ||
260 | .nid = Nv_Master_Convert_nid, | ||
261 | .rates = SNDRV_PCM_RATE_48000, | ||
262 | .maxbps = 16, | ||
263 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
264 | .ops = { | ||
265 | .open = nvhdmi_dig_playback_pcm_open, | ||
266 | .close = nvhdmi_dig_playback_pcm_close_8ch, | ||
267 | .prepare = nvhdmi_dig_playback_pcm_prepare_8ch | ||
268 | }, | ||
269 | }; | ||
270 | |||
271 | static struct hda_pcm_stream nvhdmi_pcm_digital_playback_2ch = { | ||
96 | .substreams = 1, | 272 | .substreams = 1, |
97 | .channels_min = 2, | 273 | .channels_min = 2, |
98 | .channels_max = 2, | 274 | .channels_max = 2, |
99 | .nid = 0x4, /* NID to query formats and rates and setup streams */ | 275 | .nid = Nv_Master_Convert_nid, |
100 | .rates = SNDRV_PCM_RATE_48000, | 276 | .rates = SNDRV_PCM_RATE_48000, |
101 | .maxbps = 16, | 277 | .maxbps = 16, |
102 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | 278 | .formats = SNDRV_PCM_FMTBIT_S16_LE, |
103 | .ops = { | 279 | .ops = { |
104 | .open = nvhdmi_dig_playback_pcm_open, | 280 | .open = nvhdmi_dig_playback_pcm_open, |
105 | .close = nvhdmi_dig_playback_pcm_close, | 281 | .close = nvhdmi_dig_playback_pcm_close_2ch, |
106 | .prepare = nvhdmi_dig_playback_pcm_prepare | 282 | .prepare = nvhdmi_dig_playback_pcm_prepare_2ch |
107 | }, | 283 | }, |
108 | }; | 284 | }; |
109 | 285 | ||
110 | static int nvhdmi_build_pcms(struct hda_codec *codec) | 286 | static int nvhdmi_build_pcms_8ch(struct hda_codec *codec) |
111 | { | 287 | { |
112 | struct nvhdmi_spec *spec = codec->spec; | 288 | struct nvhdmi_spec *spec = codec->spec; |
113 | struct hda_pcm *info = &spec->pcm_rec; | 289 | struct hda_pcm *info = &spec->pcm_rec; |
@@ -117,7 +293,24 @@ static int nvhdmi_build_pcms(struct hda_codec *codec) | |||
117 | 293 | ||
118 | info->name = "NVIDIA HDMI"; | 294 | info->name = "NVIDIA HDMI"; |
119 | info->pcm_type = HDA_PCM_TYPE_HDMI; | 295 | info->pcm_type = HDA_PCM_TYPE_HDMI; |
120 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = nvhdmi_pcm_digital_playback; | 296 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] |
297 | = nvhdmi_pcm_digital_playback_8ch; | ||
298 | |||
299 | return 0; | ||
300 | } | ||
301 | |||
302 | static int nvhdmi_build_pcms_2ch(struct hda_codec *codec) | ||
303 | { | ||
304 | struct nvhdmi_spec *spec = codec->spec; | ||
305 | struct hda_pcm *info = &spec->pcm_rec; | ||
306 | |||
307 | codec->num_pcms = 1; | ||
308 | codec->pcm_info = info; | ||
309 | |||
310 | info->name = "NVIDIA HDMI"; | ||
311 | info->pcm_type = HDA_PCM_TYPE_HDMI; | ||
312 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] | ||
313 | = nvhdmi_pcm_digital_playback_2ch; | ||
121 | 314 | ||
122 | return 0; | 315 | return 0; |
123 | } | 316 | } |
@@ -127,14 +320,40 @@ static void nvhdmi_free(struct hda_codec *codec) | |||
127 | kfree(codec->spec); | 320 | kfree(codec->spec); |
128 | } | 321 | } |
129 | 322 | ||
130 | static struct hda_codec_ops nvhdmi_patch_ops = { | 323 | static struct hda_codec_ops nvhdmi_patch_ops_8ch = { |
324 | .build_controls = nvhdmi_build_controls, | ||
325 | .build_pcms = nvhdmi_build_pcms_8ch, | ||
326 | .init = nvhdmi_init, | ||
327 | .free = nvhdmi_free, | ||
328 | }; | ||
329 | |||
330 | static struct hda_codec_ops nvhdmi_patch_ops_2ch = { | ||
131 | .build_controls = nvhdmi_build_controls, | 331 | .build_controls = nvhdmi_build_controls, |
132 | .build_pcms = nvhdmi_build_pcms, | 332 | .build_pcms = nvhdmi_build_pcms_2ch, |
133 | .init = nvhdmi_init, | 333 | .init = nvhdmi_init, |
134 | .free = nvhdmi_free, | 334 | .free = nvhdmi_free, |
135 | }; | 335 | }; |
136 | 336 | ||
137 | static int patch_nvhdmi(struct hda_codec *codec) | 337 | static int patch_nvhdmi_8ch(struct hda_codec *codec) |
338 | { | ||
339 | struct nvhdmi_spec *spec; | ||
340 | |||
341 | spec = kzalloc(sizeof(*spec), GFP_KERNEL); | ||
342 | if (spec == NULL) | ||
343 | return -ENOMEM; | ||
344 | |||
345 | codec->spec = spec; | ||
346 | |||
347 | spec->multiout.num_dacs = 0; /* no analog */ | ||
348 | spec->multiout.max_channels = 8; | ||
349 | spec->multiout.dig_out_nid = Nv_Master_Convert_nid; | ||
350 | |||
351 | codec->patch_ops = nvhdmi_patch_ops_8ch; | ||
352 | |||
353 | return 0; | ||
354 | } | ||
355 | |||
356 | static int patch_nvhdmi_2ch(struct hda_codec *codec) | ||
138 | { | 357 | { |
139 | struct nvhdmi_spec *spec; | 358 | struct nvhdmi_spec *spec; |
140 | 359 | ||
@@ -144,13 +363,11 @@ static int patch_nvhdmi(struct hda_codec *codec) | |||
144 | 363 | ||
145 | codec->spec = spec; | 364 | codec->spec = spec; |
146 | 365 | ||
147 | spec->multiout.num_dacs = 0; /* no analog */ | 366 | spec->multiout.num_dacs = 0; /* no analog */ |
148 | spec->multiout.max_channels = 2; | 367 | spec->multiout.max_channels = 2; |
149 | spec->multiout.dig_out_nid = 0x4; /* NID for copying analog to digital, | 368 | spec->multiout.dig_out_nid = Nv_Master_Convert_nid; |
150 | * seems to be unused in pure-digital | ||
151 | * case. */ | ||
152 | 369 | ||
153 | codec->patch_ops = nvhdmi_patch_ops; | 370 | codec->patch_ops = nvhdmi_patch_ops_2ch; |
154 | 371 | ||
155 | return 0; | 372 | return 0; |
156 | } | 373 | } |
@@ -159,11 +376,11 @@ static int patch_nvhdmi(struct hda_codec *codec) | |||
159 | * patch entries | 376 | * patch entries |
160 | */ | 377 | */ |
161 | static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { | 378 | static struct hda_codec_preset snd_hda_preset_nvhdmi[] = { |
162 | { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, | 379 | { .id = 0x10de0002, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, |
163 | { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi }, | 380 | { .id = 0x10de0006, .name = "MCP78 HDMI", .patch = patch_nvhdmi_8ch }, |
164 | { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi }, | 381 | { .id = 0x10de0007, .name = "MCP7A HDMI", .patch = patch_nvhdmi_8ch }, |
165 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi }, | 382 | { .id = 0x10de0067, .name = "MCP67 HDMI", .patch = patch_nvhdmi_2ch }, |
166 | { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi }, | 383 | { .id = 0x10de8001, .name = "MCP73 HDMI", .patch = patch_nvhdmi_2ch }, |
167 | {} /* terminator */ | 384 | {} /* terminator */ |
168 | }; | 385 | }; |
169 | 386 | ||
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index b8a0d3e79272..337d2a59c67e 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -190,6 +190,7 @@ enum { | |||
190 | ALC663_ASUS_MODE6, | 190 | ALC663_ASUS_MODE6, |
191 | ALC272_DELL, | 191 | ALC272_DELL, |
192 | ALC272_DELL_ZM1, | 192 | ALC272_DELL_ZM1, |
193 | ALC272_SAMSUNG_NC10, | ||
193 | ALC662_AUTO, | 194 | ALC662_AUTO, |
194 | ALC662_MODEL_LAST, | 195 | ALC662_MODEL_LAST, |
195 | }; | 196 | }; |
@@ -205,6 +206,7 @@ enum { | |||
205 | ALC882_ASUS_A7M, | 206 | ALC882_ASUS_A7M, |
206 | ALC885_MACPRO, | 207 | ALC885_MACPRO, |
207 | ALC885_MBP3, | 208 | ALC885_MBP3, |
209 | ALC885_MB5, | ||
208 | ALC885_IMAC24, | 210 | ALC885_IMAC24, |
209 | ALC882_AUTO, | 211 | ALC882_AUTO, |
210 | ALC882_MODEL_LAST, | 212 | ALC882_MODEL_LAST, |
@@ -218,9 +220,11 @@ enum { | |||
218 | ALC883_6ST_DIG, | 220 | ALC883_6ST_DIG, |
219 | ALC883_TARGA_DIG, | 221 | ALC883_TARGA_DIG, |
220 | ALC883_TARGA_2ch_DIG, | 222 | ALC883_TARGA_2ch_DIG, |
223 | ALC883_TARGA_8ch_DIG, | ||
221 | ALC883_ACER, | 224 | ALC883_ACER, |
222 | ALC883_ACER_ASPIRE, | 225 | ALC883_ACER_ASPIRE, |
223 | ALC888_ACER_ASPIRE_4930G, | 226 | ALC888_ACER_ASPIRE_4930G, |
227 | ALC888_ACER_ASPIRE_8930G, | ||
224 | ALC883_MEDION, | 228 | ALC883_MEDION, |
225 | ALC883_MEDION_MD2, | 229 | ALC883_MEDION_MD2, |
226 | ALC883_LAPTOP_EAPD, | 230 | ALC883_LAPTOP_EAPD, |
@@ -238,7 +242,9 @@ enum { | |||
238 | ALC883_3ST_6ch_INTEL, | 242 | ALC883_3ST_6ch_INTEL, |
239 | ALC888_ASUS_M90V, | 243 | ALC888_ASUS_M90V, |
240 | ALC888_ASUS_EEE1601, | 244 | ALC888_ASUS_EEE1601, |
245 | ALC889A_MB31, | ||
241 | ALC1200_ASUS_P5Q, | 246 | ALC1200_ASUS_P5Q, |
247 | ALC883_SONY_VAIO_TT, | ||
242 | ALC883_AUTO, | 248 | ALC883_AUTO, |
243 | ALC883_MODEL_LAST, | 249 | ALC883_MODEL_LAST, |
244 | }; | 250 | }; |
@@ -253,6 +259,15 @@ enum { | |||
253 | /* for GPIO Poll */ | 259 | /* for GPIO Poll */ |
254 | #define GPIO_MASK 0x03 | 260 | #define GPIO_MASK 0x03 |
255 | 261 | ||
262 | /* extra amp-initialization sequence types */ | ||
263 | enum { | ||
264 | ALC_INIT_NONE, | ||
265 | ALC_INIT_DEFAULT, | ||
266 | ALC_INIT_GPIO1, | ||
267 | ALC_INIT_GPIO2, | ||
268 | ALC_INIT_GPIO3, | ||
269 | }; | ||
270 | |||
256 | struct alc_spec { | 271 | struct alc_spec { |
257 | /* codec parameterization */ | 272 | /* codec parameterization */ |
258 | struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ | 273 | struct snd_kcontrol_new *mixers[5]; /* mixer arrays */ |
@@ -266,13 +281,13 @@ struct alc_spec { | |||
266 | */ | 281 | */ |
267 | unsigned int num_init_verbs; | 282 | unsigned int num_init_verbs; |
268 | 283 | ||
269 | char *stream_name_analog; /* analog PCM stream */ | 284 | char stream_name_analog[16]; /* analog PCM stream */ |
270 | struct hda_pcm_stream *stream_analog_playback; | 285 | struct hda_pcm_stream *stream_analog_playback; |
271 | struct hda_pcm_stream *stream_analog_capture; | 286 | struct hda_pcm_stream *stream_analog_capture; |
272 | struct hda_pcm_stream *stream_analog_alt_playback; | 287 | struct hda_pcm_stream *stream_analog_alt_playback; |
273 | struct hda_pcm_stream *stream_analog_alt_capture; | 288 | struct hda_pcm_stream *stream_analog_alt_capture; |
274 | 289 | ||
275 | char *stream_name_digital; /* digital PCM stream */ | 290 | char stream_name_digital[16]; /* digital PCM stream */ |
276 | struct hda_pcm_stream *stream_digital_playback; | 291 | struct hda_pcm_stream *stream_digital_playback; |
277 | struct hda_pcm_stream *stream_digital_capture; | 292 | struct hda_pcm_stream *stream_digital_capture; |
278 | 293 | ||
@@ -301,6 +316,8 @@ struct alc_spec { | |||
301 | const struct hda_channel_mode *channel_mode; | 316 | const struct hda_channel_mode *channel_mode; |
302 | int num_channel_mode; | 317 | int num_channel_mode; |
303 | int need_dac_fix; | 318 | int need_dac_fix; |
319 | int const_channel_count; | ||
320 | int ext_channel_count; | ||
304 | 321 | ||
305 | /* PCM information */ | 322 | /* PCM information */ |
306 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ | 323 | struct hda_pcm pcm_rec[3]; /* used in alc_build_pcms() */ |
@@ -322,6 +339,7 @@ struct alc_spec { | |||
322 | 339 | ||
323 | /* other flags */ | 340 | /* other flags */ |
324 | unsigned int no_analog :1; /* digital I/O only */ | 341 | unsigned int no_analog :1; /* digital I/O only */ |
342 | int init_amp; | ||
325 | 343 | ||
326 | /* for virtual master */ | 344 | /* for virtual master */ |
327 | hda_nid_t vmaster_nid; | 345 | hda_nid_t vmaster_nid; |
@@ -355,6 +373,7 @@ struct alc_config_preset { | |||
355 | unsigned int num_channel_mode; | 373 | unsigned int num_channel_mode; |
356 | const struct hda_channel_mode *channel_mode; | 374 | const struct hda_channel_mode *channel_mode; |
357 | int need_dac_fix; | 375 | int need_dac_fix; |
376 | int const_channel_count; | ||
358 | unsigned int num_mux_defs; | 377 | unsigned int num_mux_defs; |
359 | const struct hda_input_mux *input_mux; | 378 | const struct hda_input_mux *input_mux; |
360 | void (*unsol_event)(struct hda_codec *, unsigned int); | 379 | void (*unsol_event)(struct hda_codec *, unsigned int); |
@@ -449,7 +468,7 @@ static int alc_ch_mode_get(struct snd_kcontrol *kcontrol, | |||
449 | struct alc_spec *spec = codec->spec; | 468 | struct alc_spec *spec = codec->spec; |
450 | return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, | 469 | return snd_hda_ch_mode_get(codec, ucontrol, spec->channel_mode, |
451 | spec->num_channel_mode, | 470 | spec->num_channel_mode, |
452 | spec->multiout.max_channels); | 471 | spec->ext_channel_count); |
453 | } | 472 | } |
454 | 473 | ||
455 | static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, | 474 | static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, |
@@ -459,9 +478,12 @@ static int alc_ch_mode_put(struct snd_kcontrol *kcontrol, | |||
459 | struct alc_spec *spec = codec->spec; | 478 | struct alc_spec *spec = codec->spec; |
460 | int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, | 479 | int err = snd_hda_ch_mode_put(codec, ucontrol, spec->channel_mode, |
461 | spec->num_channel_mode, | 480 | spec->num_channel_mode, |
462 | &spec->multiout.max_channels); | 481 | &spec->ext_channel_count); |
463 | if (err >= 0 && spec->need_dac_fix) | 482 | if (err >= 0 && !spec->const_channel_count) { |
464 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | 483 | spec->multiout.max_channels = spec->ext_channel_count; |
484 | if (spec->need_dac_fix) | ||
485 | spec->multiout.num_dacs = spec->multiout.max_channels / 2; | ||
486 | } | ||
465 | return err; | 487 | return err; |
466 | } | 488 | } |
467 | 489 | ||
@@ -776,6 +798,12 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, | |||
776 | pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; | 798 | pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; |
777 | if (pincap & AC_PINCAP_VREF_80) | 799 | if (pincap & AC_PINCAP_VREF_80) |
778 | val = PIN_VREF80; | 800 | val = PIN_VREF80; |
801 | else if (pincap & AC_PINCAP_VREF_50) | ||
802 | val = PIN_VREF50; | ||
803 | else if (pincap & AC_PINCAP_VREF_100) | ||
804 | val = PIN_VREF100; | ||
805 | else if (pincap & AC_PINCAP_VREF_GRD) | ||
806 | val = PIN_VREFGRD; | ||
779 | } | 807 | } |
780 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); | 808 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); |
781 | } | 809 | } |
@@ -835,8 +863,13 @@ static void setup_preset(struct alc_spec *spec, | |||
835 | spec->channel_mode = preset->channel_mode; | 863 | spec->channel_mode = preset->channel_mode; |
836 | spec->num_channel_mode = preset->num_channel_mode; | 864 | spec->num_channel_mode = preset->num_channel_mode; |
837 | spec->need_dac_fix = preset->need_dac_fix; | 865 | spec->need_dac_fix = preset->need_dac_fix; |
866 | spec->const_channel_count = preset->const_channel_count; | ||
838 | 867 | ||
839 | spec->multiout.max_channels = spec->channel_mode[0].channels; | 868 | if (preset->const_channel_count) |
869 | spec->multiout.max_channels = preset->const_channel_count; | ||
870 | else | ||
871 | spec->multiout.max_channels = spec->channel_mode[0].channels; | ||
872 | spec->ext_channel_count = spec->channel_mode[0].channels; | ||
840 | 873 | ||
841 | spec->multiout.num_dacs = preset->num_dacs; | 874 | spec->multiout.num_dacs = preset->num_dacs; |
842 | spec->multiout.dac_nids = preset->dac_nids; | 875 | spec->multiout.dac_nids = preset->dac_nids; |
@@ -915,20 +948,26 @@ static void alc_fix_pll_init(struct hda_codec *codec, hda_nid_t nid, | |||
915 | alc_fix_pll(codec); | 948 | alc_fix_pll(codec); |
916 | } | 949 | } |
917 | 950 | ||
918 | static void alc_sku_automute(struct hda_codec *codec) | 951 | static void alc_automute_pin(struct hda_codec *codec) |
919 | { | 952 | { |
920 | struct alc_spec *spec = codec->spec; | 953 | struct alc_spec *spec = codec->spec; |
921 | unsigned int present; | 954 | unsigned int present; |
922 | unsigned int hp_nid = spec->autocfg.hp_pins[0]; | 955 | unsigned int nid = spec->autocfg.hp_pins[0]; |
923 | unsigned int sp_nid = spec->autocfg.speaker_pins[0]; | 956 | int i; |
924 | 957 | ||
925 | /* need to execute and sync at first */ | 958 | /* need to execute and sync at first */ |
926 | snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); | 959 | snd_hda_codec_read(codec, nid, 0, AC_VERB_SET_PIN_SENSE, 0); |
927 | present = snd_hda_codec_read(codec, hp_nid, 0, | 960 | present = snd_hda_codec_read(codec, nid, 0, |
928 | AC_VERB_GET_PIN_SENSE, 0); | 961 | AC_VERB_GET_PIN_SENSE, 0); |
929 | spec->jack_present = (present & 0x80000000) != 0; | 962 | spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; |
930 | snd_hda_codec_write(codec, sp_nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 963 | for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { |
931 | spec->jack_present ? 0 : PIN_OUT); | 964 | nid = spec->autocfg.speaker_pins[i]; |
965 | if (!nid) | ||
966 | break; | ||
967 | snd_hda_codec_write(codec, nid, 0, | ||
968 | AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
969 | spec->jack_present ? 0 : PIN_OUT); | ||
970 | } | ||
932 | } | 971 | } |
933 | 972 | ||
934 | #if 0 /* it's broken in some acses -- temporarily disabled */ | 973 | #if 0 /* it's broken in some acses -- temporarily disabled */ |
@@ -963,16 +1002,19 @@ static void alc_sku_unsol_event(struct hda_codec *codec, unsigned int res) | |||
963 | res >>= 28; | 1002 | res >>= 28; |
964 | else | 1003 | else |
965 | res >>= 26; | 1004 | res >>= 26; |
966 | if (res == ALC880_HP_EVENT) | 1005 | switch (res) { |
967 | alc_sku_automute(codec); | 1006 | case ALC880_HP_EVENT: |
968 | 1007 | alc_automute_pin(codec); | |
969 | if (res == ALC880_MIC_EVENT) | 1008 | break; |
1009 | case ALC880_MIC_EVENT: | ||
970 | alc_mic_automute(codec); | 1010 | alc_mic_automute(codec); |
1011 | break; | ||
1012 | } | ||
971 | } | 1013 | } |
972 | 1014 | ||
973 | static void alc_inithook(struct hda_codec *codec) | 1015 | static void alc_inithook(struct hda_codec *codec) |
974 | { | 1016 | { |
975 | alc_sku_automute(codec); | 1017 | alc_automute_pin(codec); |
976 | alc_mic_automute(codec); | 1018 | alc_mic_automute(codec); |
977 | } | 1019 | } |
978 | 1020 | ||
@@ -994,69 +1036,21 @@ static void alc888_coef_init(struct hda_codec *codec) | |||
994 | AC_VERB_SET_PROC_COEF, 0x3030); | 1036 | AC_VERB_SET_PROC_COEF, 0x3030); |
995 | } | 1037 | } |
996 | 1038 | ||
997 | /* 32-bit subsystem ID for BIOS loading in HD Audio codec. | 1039 | static void alc_auto_init_amp(struct hda_codec *codec, int type) |
998 | * 31 ~ 16 : Manufacture ID | ||
999 | * 15 ~ 8 : SKU ID | ||
1000 | * 7 ~ 0 : Assembly ID | ||
1001 | * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 | ||
1002 | */ | ||
1003 | static void alc_subsystem_id(struct hda_codec *codec, | ||
1004 | unsigned int porta, unsigned int porte, | ||
1005 | unsigned int portd) | ||
1006 | { | 1040 | { |
1007 | unsigned int ass, tmp, i; | 1041 | unsigned int tmp; |
1008 | unsigned nid; | ||
1009 | struct alc_spec *spec = codec->spec; | ||
1010 | |||
1011 | ass = codec->subsystem_id & 0xffff; | ||
1012 | if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) | ||
1013 | goto do_sku; | ||
1014 | |||
1015 | /* | ||
1016 | * 31~30 : port conetcivity | ||
1017 | * 29~21 : reserve | ||
1018 | * 20 : PCBEEP input | ||
1019 | * 19~16 : Check sum (15:1) | ||
1020 | * 15~1 : Custom | ||
1021 | * 0 : override | ||
1022 | */ | ||
1023 | nid = 0x1d; | ||
1024 | if (codec->vendor_id == 0x10ec0260) | ||
1025 | nid = 0x17; | ||
1026 | ass = snd_hda_codec_get_pincfg(codec, nid); | ||
1027 | if (!(ass & 1) && !(ass & 0x100000)) | ||
1028 | return; | ||
1029 | if ((ass >> 30) != 1) /* no physical connection */ | ||
1030 | return; | ||
1031 | 1042 | ||
1032 | /* check sum */ | 1043 | switch (type) { |
1033 | tmp = 0; | 1044 | case ALC_INIT_GPIO1: |
1034 | for (i = 1; i < 16; i++) { | ||
1035 | if ((ass >> i) & 1) | ||
1036 | tmp++; | ||
1037 | } | ||
1038 | if (((ass >> 16) & 0xf) != tmp) | ||
1039 | return; | ||
1040 | do_sku: | ||
1041 | /* | ||
1042 | * 0 : override | ||
1043 | * 1 : Swap Jack | ||
1044 | * 2 : 0 --> Desktop, 1 --> Laptop | ||
1045 | * 3~5 : External Amplifier control | ||
1046 | * 7~6 : Reserved | ||
1047 | */ | ||
1048 | tmp = (ass & 0x38) >> 3; /* external Amp control */ | ||
1049 | switch (tmp) { | ||
1050 | case 1: | ||
1051 | snd_hda_sequence_write(codec, alc_gpio1_init_verbs); | 1045 | snd_hda_sequence_write(codec, alc_gpio1_init_verbs); |
1052 | break; | 1046 | break; |
1053 | case 3: | 1047 | case ALC_INIT_GPIO2: |
1054 | snd_hda_sequence_write(codec, alc_gpio2_init_verbs); | 1048 | snd_hda_sequence_write(codec, alc_gpio2_init_verbs); |
1055 | break; | 1049 | break; |
1056 | case 7: | 1050 | case ALC_INIT_GPIO3: |
1057 | snd_hda_sequence_write(codec, alc_gpio3_init_verbs); | 1051 | snd_hda_sequence_write(codec, alc_gpio3_init_verbs); |
1058 | break; | 1052 | break; |
1059 | case 5: /* set EAPD output high */ | 1053 | case ALC_INIT_DEFAULT: |
1060 | switch (codec->vendor_id) { | 1054 | switch (codec->vendor_id) { |
1061 | case 0x10ec0260: | 1055 | case 0x10ec0260: |
1062 | snd_hda_codec_write(codec, 0x0f, 0, | 1056 | snd_hda_codec_write(codec, 0x0f, 0, |
@@ -1110,7 +1104,7 @@ do_sku: | |||
1110 | tmp | 0x2010); | 1104 | tmp | 0x2010); |
1111 | break; | 1105 | break; |
1112 | case 0x10ec0888: | 1106 | case 0x10ec0888: |
1113 | /*alc888_coef_init(codec);*/ /* called in alc_init() */ | 1107 | alc888_coef_init(codec); |
1114 | break; | 1108 | break; |
1115 | case 0x10ec0267: | 1109 | case 0x10ec0267: |
1116 | case 0x10ec0268: | 1110 | case 0x10ec0268: |
@@ -1125,7 +1119,107 @@ do_sku: | |||
1125 | tmp | 0x3000); | 1119 | tmp | 0x3000); |
1126 | break; | 1120 | break; |
1127 | } | 1121 | } |
1128 | default: | 1122 | break; |
1123 | } | ||
1124 | } | ||
1125 | |||
1126 | static void alc_init_auto_hp(struct hda_codec *codec) | ||
1127 | { | ||
1128 | struct alc_spec *spec = codec->spec; | ||
1129 | |||
1130 | if (!spec->autocfg.hp_pins[0]) | ||
1131 | return; | ||
1132 | |||
1133 | if (!spec->autocfg.speaker_pins[0]) { | ||
1134 | if (spec->autocfg.line_out_pins[0] && | ||
1135 | spec->autocfg.line_out_type == AUTO_PIN_SPEAKER_OUT) | ||
1136 | spec->autocfg.speaker_pins[0] = | ||
1137 | spec->autocfg.line_out_pins[0]; | ||
1138 | else | ||
1139 | return; | ||
1140 | } | ||
1141 | |||
1142 | snd_printdd("realtek: Enable HP auto-muting on NID 0x%x\n", | ||
1143 | spec->autocfg.hp_pins[0]); | ||
1144 | snd_hda_codec_write_cache(codec, spec->autocfg.hp_pins[0], 0, | ||
1145 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1146 | AC_USRSP_EN | ALC880_HP_EVENT); | ||
1147 | spec->unsol_event = alc_sku_unsol_event; | ||
1148 | } | ||
1149 | |||
1150 | /* check subsystem ID and set up device-specific initialization; | ||
1151 | * return 1 if initialized, 0 if invalid SSID | ||
1152 | */ | ||
1153 | /* 32-bit subsystem ID for BIOS loading in HD Audio codec. | ||
1154 | * 31 ~ 16 : Manufacture ID | ||
1155 | * 15 ~ 8 : SKU ID | ||
1156 | * 7 ~ 0 : Assembly ID | ||
1157 | * port-A --> pin 39/41, port-E --> pin 14/15, port-D --> pin 35/36 | ||
1158 | */ | ||
1159 | static int alc_subsystem_id(struct hda_codec *codec, | ||
1160 | hda_nid_t porta, hda_nid_t porte, | ||
1161 | hda_nid_t portd) | ||
1162 | { | ||
1163 | unsigned int ass, tmp, i; | ||
1164 | unsigned nid; | ||
1165 | struct alc_spec *spec = codec->spec; | ||
1166 | |||
1167 | ass = codec->subsystem_id & 0xffff; | ||
1168 | if ((ass != codec->bus->pci->subsystem_device) && (ass & 1)) | ||
1169 | goto do_sku; | ||
1170 | |||
1171 | /* invalid SSID, check the special NID pin defcfg instead */ | ||
1172 | /* | ||
1173 | * 31~30 : port conetcivity | ||
1174 | * 29~21 : reserve | ||
1175 | * 20 : PCBEEP input | ||
1176 | * 19~16 : Check sum (15:1) | ||
1177 | * 15~1 : Custom | ||
1178 | * 0 : override | ||
1179 | */ | ||
1180 | nid = 0x1d; | ||
1181 | if (codec->vendor_id == 0x10ec0260) | ||
1182 | nid = 0x17; | ||
1183 | ass = snd_hda_codec_get_pincfg(codec, nid); | ||
1184 | snd_printd("realtek: No valid SSID, " | ||
1185 | "checking pincfg 0x%08x for NID 0x%x\n", | ||
1186 | ass, nid); | ||
1187 | if (!(ass & 1) && !(ass & 0x100000)) | ||
1188 | return 0; | ||
1189 | if ((ass >> 30) != 1) /* no physical connection */ | ||
1190 | return 0; | ||
1191 | |||
1192 | /* check sum */ | ||
1193 | tmp = 0; | ||
1194 | for (i = 1; i < 16; i++) { | ||
1195 | if ((ass >> i) & 1) | ||
1196 | tmp++; | ||
1197 | } | ||
1198 | if (((ass >> 16) & 0xf) != tmp) | ||
1199 | return 0; | ||
1200 | do_sku: | ||
1201 | snd_printd("realtek: Enabling init ASM_ID=0x%04x CODEC_ID=%08x\n", | ||
1202 | ass & 0xffff, codec->vendor_id); | ||
1203 | /* | ||
1204 | * 0 : override | ||
1205 | * 1 : Swap Jack | ||
1206 | * 2 : 0 --> Desktop, 1 --> Laptop | ||
1207 | * 3~5 : External Amplifier control | ||
1208 | * 7~6 : Reserved | ||
1209 | */ | ||
1210 | tmp = (ass & 0x38) >> 3; /* external Amp control */ | ||
1211 | switch (tmp) { | ||
1212 | case 1: | ||
1213 | spec->init_amp = ALC_INIT_GPIO1; | ||
1214 | break; | ||
1215 | case 3: | ||
1216 | spec->init_amp = ALC_INIT_GPIO2; | ||
1217 | break; | ||
1218 | case 7: | ||
1219 | spec->init_amp = ALC_INIT_GPIO3; | ||
1220 | break; | ||
1221 | case 5: | ||
1222 | spec->init_amp = ALC_INIT_DEFAULT; | ||
1129 | break; | 1223 | break; |
1130 | } | 1224 | } |
1131 | 1225 | ||
@@ -1133,7 +1227,7 @@ do_sku: | |||
1133 | * when the external headphone out jack is plugged" | 1227 | * when the external headphone out jack is plugged" |
1134 | */ | 1228 | */ |
1135 | if (!(ass & 0x8000)) | 1229 | if (!(ass & 0x8000)) |
1136 | return; | 1230 | return 1; |
1137 | /* | 1231 | /* |
1138 | * 10~8 : Jack location | 1232 | * 10~8 : Jack location |
1139 | * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered | 1233 | * 12~11: Headphone out -> 00: PortA, 01: PortE, 02: PortD, 03: Resvered |
@@ -1141,14 +1235,6 @@ do_sku: | |||
1141 | * 15 : 1 --> enable the function "Mute internal speaker | 1235 | * 15 : 1 --> enable the function "Mute internal speaker |
1142 | * when the external headphone out jack is plugged" | 1236 | * when the external headphone out jack is plugged" |
1143 | */ | 1237 | */ |
1144 | if (!spec->autocfg.speaker_pins[0]) { | ||
1145 | if (spec->autocfg.line_out_pins[0]) | ||
1146 | spec->autocfg.speaker_pins[0] = | ||
1147 | spec->autocfg.line_out_pins[0]; | ||
1148 | else | ||
1149 | return; | ||
1150 | } | ||
1151 | |||
1152 | if (!spec->autocfg.hp_pins[0]) { | 1238 | if (!spec->autocfg.hp_pins[0]) { |
1153 | tmp = (ass >> 11) & 0x3; /* HP to chassis */ | 1239 | tmp = (ass >> 11) & 0x3; /* HP to chassis */ |
1154 | if (tmp == 0) | 1240 | if (tmp == 0) |
@@ -1158,23 +1244,23 @@ do_sku: | |||
1158 | else if (tmp == 2) | 1244 | else if (tmp == 2) |
1159 | spec->autocfg.hp_pins[0] = portd; | 1245 | spec->autocfg.hp_pins[0] = portd; |
1160 | else | 1246 | else |
1161 | return; | 1247 | return 1; |
1162 | } | 1248 | } |
1163 | if (spec->autocfg.hp_pins[0]) | ||
1164 | snd_hda_codec_write(codec, spec->autocfg.hp_pins[0], 0, | ||
1165 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1166 | AC_USRSP_EN | ALC880_HP_EVENT); | ||
1167 | 1249 | ||
1168 | #if 0 /* it's broken in some acses -- temporarily disabled */ | 1250 | alc_init_auto_hp(codec); |
1169 | if (spec->autocfg.input_pins[AUTO_PIN_MIC] && | 1251 | return 1; |
1170 | spec->autocfg.input_pins[AUTO_PIN_FRONT_MIC]) | 1252 | } |
1171 | snd_hda_codec_write(codec, | ||
1172 | spec->autocfg.input_pins[AUTO_PIN_MIC], 0, | ||
1173 | AC_VERB_SET_UNSOLICITED_ENABLE, | ||
1174 | AC_USRSP_EN | ALC880_MIC_EVENT); | ||
1175 | #endif /* disabled */ | ||
1176 | 1253 | ||
1177 | spec->unsol_event = alc_sku_unsol_event; | 1254 | static void alc_ssid_check(struct hda_codec *codec, |
1255 | hda_nid_t porta, hda_nid_t porte, hda_nid_t portd) | ||
1256 | { | ||
1257 | if (!alc_subsystem_id(codec, porta, porte, portd)) { | ||
1258 | struct alc_spec *spec = codec->spec; | ||
1259 | snd_printd("realtek: " | ||
1260 | "Enable default setup for auto mode as fallback\n"); | ||
1261 | spec->init_amp = ALC_INIT_DEFAULT; | ||
1262 | alc_init_auto_hp(codec); | ||
1263 | } | ||
1178 | } | 1264 | } |
1179 | 1265 | ||
1180 | /* | 1266 | /* |
@@ -1309,32 +1395,58 @@ static struct hda_verb alc888_fujitsu_xa3530_verbs[] = { | |||
1309 | {} | 1395 | {} |
1310 | }; | 1396 | }; |
1311 | 1397 | ||
1312 | static void alc888_fujitsu_xa3530_automute(struct hda_codec *codec) | 1398 | static void alc_automute_amp(struct hda_codec *codec) |
1313 | { | 1399 | { |
1314 | unsigned int present; | 1400 | struct alc_spec *spec = codec->spec; |
1315 | unsigned int bits; | 1401 | unsigned int val, mute; |
1316 | /* Line out presence */ | 1402 | hda_nid_t nid; |
1317 | present = snd_hda_codec_read(codec, 0x17, 0, | 1403 | int i; |
1318 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1404 | |
1319 | /* HP out presence */ | 1405 | spec->jack_present = 0; |
1320 | present = present || snd_hda_codec_read(codec, 0x1b, 0, | 1406 | for (i = 0; i < ARRAY_SIZE(spec->autocfg.hp_pins); i++) { |
1321 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1407 | nid = spec->autocfg.hp_pins[i]; |
1322 | bits = present ? HDA_AMP_MUTE : 0; | 1408 | if (!nid) |
1409 | break; | ||
1410 | val = snd_hda_codec_read(codec, nid, 0, | ||
1411 | AC_VERB_GET_PIN_SENSE, 0); | ||
1412 | if (val & AC_PINSENSE_PRESENCE) { | ||
1413 | spec->jack_present = 1; | ||
1414 | break; | ||
1415 | } | ||
1416 | } | ||
1417 | |||
1418 | mute = spec->jack_present ? HDA_AMP_MUTE : 0; | ||
1323 | /* Toggle internal speakers muting */ | 1419 | /* Toggle internal speakers muting */ |
1324 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | 1420 | for (i = 0; i < ARRAY_SIZE(spec->autocfg.speaker_pins); i++) { |
1325 | HDA_AMP_MUTE, bits); | 1421 | nid = spec->autocfg.speaker_pins[i]; |
1326 | /* Toggle internal bass muting */ | 1422 | if (!nid) |
1327 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | 1423 | break; |
1328 | HDA_AMP_MUTE, bits); | 1424 | snd_hda_codec_amp_stereo(codec, nid, HDA_OUTPUT, 0, |
1425 | HDA_AMP_MUTE, mute); | ||
1426 | } | ||
1329 | } | 1427 | } |
1330 | 1428 | ||
1331 | static void alc888_fujitsu_xa3530_unsol_event(struct hda_codec *codec, | 1429 | static void alc_automute_amp_unsol_event(struct hda_codec *codec, |
1332 | unsigned int res) | 1430 | unsigned int res) |
1333 | { | 1431 | { |
1334 | if (res >> 26 == ALC880_HP_EVENT) | 1432 | if (codec->vendor_id == 0x10ec0880) |
1335 | alc888_fujitsu_xa3530_automute(codec); | 1433 | res >>= 28; |
1434 | else | ||
1435 | res >>= 26; | ||
1436 | if (res == ALC880_HP_EVENT) | ||
1437 | alc_automute_amp(codec); | ||
1336 | } | 1438 | } |
1337 | 1439 | ||
1440 | static void alc888_fujitsu_xa3530_init_hook(struct hda_codec *codec) | ||
1441 | { | ||
1442 | struct alc_spec *spec = codec->spec; | ||
1443 | |||
1444 | spec->autocfg.hp_pins[0] = 0x17; /* line-out */ | ||
1445 | spec->autocfg.hp_pins[1] = 0x1b; /* hp */ | ||
1446 | spec->autocfg.speaker_pins[0] = 0x14; /* speaker */ | ||
1447 | spec->autocfg.speaker_pins[1] = 0x15; /* bass */ | ||
1448 | alc_automute_amp(codec); | ||
1449 | } | ||
1338 | 1450 | ||
1339 | /* | 1451 | /* |
1340 | * ALC888 Acer Aspire 4930G model | 1452 | * ALC888 Acer Aspire 4930G model |
@@ -1358,6 +1470,59 @@ static struct hda_verb alc888_acer_aspire_4930g_verbs[] = { | |||
1358 | { } | 1470 | { } |
1359 | }; | 1471 | }; |
1360 | 1472 | ||
1473 | /* | ||
1474 | * ALC889 Acer Aspire 8930G model | ||
1475 | */ | ||
1476 | |||
1477 | static struct hda_verb alc889_acer_aspire_8930g_verbs[] = { | ||
1478 | /* Front Mic: set to PIN_IN (empty by default) */ | ||
1479 | {0x12, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
1480 | /* Unselect Front Mic by default in input mixer 3 */ | ||
1481 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0xb)}, | ||
1482 | /* Enable unsolicited event for HP jack */ | ||
1483 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
1484 | /* Connect Internal Front to Front */ | ||
1485 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1486 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1487 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1488 | /* Connect Internal Rear to Rear */ | ||
1489 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1490 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1491 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
1492 | /* Connect Internal CLFE to CLFE */ | ||
1493 | {0x16, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
1494 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1495 | {0x16, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
1496 | /* Connect HP out to Front */ | ||
1497 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | PIN_HP}, | ||
1498 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
1499 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
1500 | /* Enable all DACs */ | ||
1501 | /* DAC DISABLE/MUTE 1? */ | ||
1502 | /* setting bits 1-5 disables DAC nids 0x02-0x06 apparently. Init=0x38 */ | ||
1503 | {0x20, AC_VERB_SET_COEF_INDEX, 0x03}, | ||
1504 | {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, | ||
1505 | /* DAC DISABLE/MUTE 2? */ | ||
1506 | /* some bit here disables the other DACs. Init=0x4900 */ | ||
1507 | {0x20, AC_VERB_SET_COEF_INDEX, 0x08}, | ||
1508 | {0x20, AC_VERB_SET_PROC_COEF, 0x0000}, | ||
1509 | /* Enable amplifiers */ | ||
1510 | {0x14, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
1511 | {0x15, AC_VERB_SET_EAPD_BTLENABLE, 0x02}, | ||
1512 | /* DMIC fix | ||
1513 | * This laptop has a stereo digital microphone. The mics are only 1cm apart | ||
1514 | * which makes the stereo useless. However, either the mic or the ALC889 | ||
1515 | * makes the signal become a difference/sum signal instead of standard | ||
1516 | * stereo, which is annoying. So instead we flip this bit which makes the | ||
1517 | * codec replicate the sum signal to both channels, turning it into a | ||
1518 | * normal mono mic. | ||
1519 | */ | ||
1520 | /* DMIC_CONTROL? Init value = 0x0001 */ | ||
1521 | {0x20, AC_VERB_SET_COEF_INDEX, 0x0b}, | ||
1522 | {0x20, AC_VERB_SET_PROC_COEF, 0x0003}, | ||
1523 | { } | ||
1524 | }; | ||
1525 | |||
1361 | static struct hda_input_mux alc888_2_capture_sources[2] = { | 1526 | static struct hda_input_mux alc888_2_capture_sources[2] = { |
1362 | /* Front mic only available on one ADC */ | 1527 | /* Front mic only available on one ADC */ |
1363 | { | 1528 | { |
@@ -1379,6 +1544,38 @@ static struct hda_input_mux alc888_2_capture_sources[2] = { | |||
1379 | } | 1544 | } |
1380 | }; | 1545 | }; |
1381 | 1546 | ||
1547 | static struct hda_input_mux alc889_capture_sources[3] = { | ||
1548 | /* Digital mic only available on first "ADC" */ | ||
1549 | { | ||
1550 | .num_items = 5, | ||
1551 | .items = { | ||
1552 | { "Mic", 0x0 }, | ||
1553 | { "Line", 0x2 }, | ||
1554 | { "CD", 0x4 }, | ||
1555 | { "Front Mic", 0xb }, | ||
1556 | { "Input Mix", 0xa }, | ||
1557 | }, | ||
1558 | }, | ||
1559 | { | ||
1560 | .num_items = 4, | ||
1561 | .items = { | ||
1562 | { "Mic", 0x0 }, | ||
1563 | { "Line", 0x2 }, | ||
1564 | { "CD", 0x4 }, | ||
1565 | { "Input Mix", 0xa }, | ||
1566 | }, | ||
1567 | }, | ||
1568 | { | ||
1569 | .num_items = 4, | ||
1570 | .items = { | ||
1571 | { "Mic", 0x0 }, | ||
1572 | { "Line", 0x2 }, | ||
1573 | { "CD", 0x4 }, | ||
1574 | { "Input Mix", 0xa }, | ||
1575 | }, | ||
1576 | } | ||
1577 | }; | ||
1578 | |||
1382 | static struct snd_kcontrol_new alc888_base_mixer[] = { | 1579 | static struct snd_kcontrol_new alc888_base_mixer[] = { |
1383 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 1580 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
1384 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 1581 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
@@ -1401,22 +1598,24 @@ static struct snd_kcontrol_new alc888_base_mixer[] = { | |||
1401 | { } /* end */ | 1598 | { } /* end */ |
1402 | }; | 1599 | }; |
1403 | 1600 | ||
1404 | static void alc888_acer_aspire_4930g_automute(struct hda_codec *codec) | 1601 | static void alc888_acer_aspire_4930g_init_hook(struct hda_codec *codec) |
1405 | { | 1602 | { |
1406 | unsigned int present; | 1603 | struct alc_spec *spec = codec->spec; |
1407 | unsigned int bits; | 1604 | |
1408 | present = snd_hda_codec_read(codec, 0x15, 0, | 1605 | spec->autocfg.hp_pins[0] = 0x15; |
1409 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 1606 | spec->autocfg.speaker_pins[0] = 0x14; |
1410 | bits = present ? HDA_AMP_MUTE : 0; | 1607 | alc_automute_amp(codec); |
1411 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
1412 | HDA_AMP_MUTE, bits); | ||
1413 | } | 1608 | } |
1414 | 1609 | ||
1415 | static void alc888_acer_aspire_4930g_unsol_event(struct hda_codec *codec, | 1610 | static void alc889_acer_aspire_8930g_init_hook(struct hda_codec *codec) |
1416 | unsigned int res) | ||
1417 | { | 1611 | { |
1418 | if (res >> 26 == ALC880_HP_EVENT) | 1612 | struct alc_spec *spec = codec->spec; |
1419 | alc888_acer_aspire_4930g_automute(codec); | 1613 | |
1614 | spec->autocfg.hp_pins[0] = 0x15; | ||
1615 | spec->autocfg.speaker_pins[0] = 0x14; | ||
1616 | spec->autocfg.speaker_pins[1] = 0x16; | ||
1617 | spec->autocfg.speaker_pins[2] = 0x1b; | ||
1618 | alc_automute_amp(codec); | ||
1420 | } | 1619 | } |
1421 | 1620 | ||
1422 | /* | 1621 | /* |
@@ -2384,21 +2583,6 @@ static struct hda_verb alc880_beep_init_verbs[] = { | |||
2384 | { } | 2583 | { } |
2385 | }; | 2584 | }; |
2386 | 2585 | ||
2387 | /* toggle speaker-output according to the hp-jack state */ | ||
2388 | static void alc880_uniwill_hp_automute(struct hda_codec *codec) | ||
2389 | { | ||
2390 | unsigned int present; | ||
2391 | unsigned char bits; | ||
2392 | |||
2393 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
2394 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2395 | bits = present ? HDA_AMP_MUTE : 0; | ||
2396 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
2397 | HDA_AMP_MUTE, bits); | ||
2398 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
2399 | HDA_AMP_MUTE, bits); | ||
2400 | } | ||
2401 | |||
2402 | /* auto-toggle front mic */ | 2586 | /* auto-toggle front mic */ |
2403 | static void alc880_uniwill_mic_automute(struct hda_codec *codec) | 2587 | static void alc880_uniwill_mic_automute(struct hda_codec *codec) |
2404 | { | 2588 | { |
@@ -2411,9 +2595,14 @@ static void alc880_uniwill_mic_automute(struct hda_codec *codec) | |||
2411 | snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); | 2595 | snd_hda_codec_amp_stereo(codec, 0x0b, HDA_INPUT, 1, HDA_AMP_MUTE, bits); |
2412 | } | 2596 | } |
2413 | 2597 | ||
2414 | static void alc880_uniwill_automute(struct hda_codec *codec) | 2598 | static void alc880_uniwill_init_hook(struct hda_codec *codec) |
2415 | { | 2599 | { |
2416 | alc880_uniwill_hp_automute(codec); | 2600 | struct alc_spec *spec = codec->spec; |
2601 | |||
2602 | spec->autocfg.hp_pins[0] = 0x14; | ||
2603 | spec->autocfg.speaker_pins[0] = 0x15; | ||
2604 | spec->autocfg.speaker_pins[0] = 0x16; | ||
2605 | alc_automute_amp(codec); | ||
2417 | alc880_uniwill_mic_automute(codec); | 2606 | alc880_uniwill_mic_automute(codec); |
2418 | } | 2607 | } |
2419 | 2608 | ||
@@ -2424,24 +2613,22 @@ static void alc880_uniwill_unsol_event(struct hda_codec *codec, | |||
2424 | * definition. 4bit tag is placed at 28 bit! | 2613 | * definition. 4bit tag is placed at 28 bit! |
2425 | */ | 2614 | */ |
2426 | switch (res >> 28) { | 2615 | switch (res >> 28) { |
2427 | case ALC880_HP_EVENT: | ||
2428 | alc880_uniwill_hp_automute(codec); | ||
2429 | break; | ||
2430 | case ALC880_MIC_EVENT: | 2616 | case ALC880_MIC_EVENT: |
2431 | alc880_uniwill_mic_automute(codec); | 2617 | alc880_uniwill_mic_automute(codec); |
2432 | break; | 2618 | break; |
2619 | default: | ||
2620 | alc_automute_amp_unsol_event(codec, res); | ||
2621 | break; | ||
2433 | } | 2622 | } |
2434 | } | 2623 | } |
2435 | 2624 | ||
2436 | static void alc880_uniwill_p53_hp_automute(struct hda_codec *codec) | 2625 | static void alc880_uniwill_p53_init_hook(struct hda_codec *codec) |
2437 | { | 2626 | { |
2438 | unsigned int present; | 2627 | struct alc_spec *spec = codec->spec; |
2439 | unsigned char bits; | ||
2440 | 2628 | ||
2441 | present = snd_hda_codec_read(codec, 0x14, 0, | 2629 | spec->autocfg.hp_pins[0] = 0x14; |
2442 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 2630 | spec->autocfg.speaker_pins[0] = 0x15; |
2443 | bits = present ? HDA_AMP_MUTE : 0; | 2631 | alc_automute_amp(codec); |
2444 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, HDA_AMP_MUTE, bits); | ||
2445 | } | 2632 | } |
2446 | 2633 | ||
2447 | static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) | 2634 | static void alc880_uniwill_p53_dcvol_automute(struct hda_codec *codec) |
@@ -2463,10 +2650,10 @@ static void alc880_uniwill_p53_unsol_event(struct hda_codec *codec, | |||
2463 | /* Looks like the unsol event is incompatible with the standard | 2650 | /* Looks like the unsol event is incompatible with the standard |
2464 | * definition. 4bit tag is placed at 28 bit! | 2651 | * definition. 4bit tag is placed at 28 bit! |
2465 | */ | 2652 | */ |
2466 | if ((res >> 28) == ALC880_HP_EVENT) | ||
2467 | alc880_uniwill_p53_hp_automute(codec); | ||
2468 | if ((res >> 28) == ALC880_DCVOL_EVENT) | 2653 | if ((res >> 28) == ALC880_DCVOL_EVENT) |
2469 | alc880_uniwill_p53_dcvol_automute(codec); | 2654 | alc880_uniwill_p53_dcvol_automute(codec); |
2655 | else | ||
2656 | alc_automute_amp_unsol_event(codec, res); | ||
2470 | } | 2657 | } |
2471 | 2658 | ||
2472 | /* | 2659 | /* |
@@ -2536,6 +2723,7 @@ static struct hda_verb alc880_pin_asus_init_verbs[] = { | |||
2536 | /* Enable GPIO mask and set output */ | 2723 | /* Enable GPIO mask and set output */ |
2537 | #define alc880_gpio1_init_verbs alc_gpio1_init_verbs | 2724 | #define alc880_gpio1_init_verbs alc_gpio1_init_verbs |
2538 | #define alc880_gpio2_init_verbs alc_gpio2_init_verbs | 2725 | #define alc880_gpio2_init_verbs alc_gpio2_init_verbs |
2726 | #define alc880_gpio3_init_verbs alc_gpio3_init_verbs | ||
2539 | 2727 | ||
2540 | /* Clevo m520g init */ | 2728 | /* Clevo m520g init */ |
2541 | static struct hda_verb alc880_pin_clevo_init_verbs[] = { | 2729 | static struct hda_verb alc880_pin_clevo_init_verbs[] = { |
@@ -2698,30 +2886,18 @@ static struct hda_verb alc880_lg_init_verbs[] = { | |||
2698 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | 2886 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
2699 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 2887 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
2700 | /* jack sense */ | 2888 | /* jack sense */ |
2701 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, | 2889 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, |
2702 | { } | 2890 | { } |
2703 | }; | 2891 | }; |
2704 | 2892 | ||
2705 | /* toggle speaker-output according to the hp-jack state */ | 2893 | /* toggle speaker-output according to the hp-jack state */ |
2706 | static void alc880_lg_automute(struct hda_codec *codec) | 2894 | static void alc880_lg_init_hook(struct hda_codec *codec) |
2707 | { | 2895 | { |
2708 | unsigned int present; | 2896 | struct alc_spec *spec = codec->spec; |
2709 | unsigned char bits; | ||
2710 | |||
2711 | present = snd_hda_codec_read(codec, 0x1b, 0, | ||
2712 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
2713 | bits = present ? HDA_AMP_MUTE : 0; | ||
2714 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
2715 | HDA_AMP_MUTE, bits); | ||
2716 | } | ||
2717 | 2897 | ||
2718 | static void alc880_lg_unsol_event(struct hda_codec *codec, unsigned int res) | 2898 | spec->autocfg.hp_pins[0] = 0x1b; |
2719 | { | 2899 | spec->autocfg.speaker_pins[0] = 0x17; |
2720 | /* Looks like the unsol event is incompatible with the standard | 2900 | alc_automute_amp(codec); |
2721 | * definition. 4bit tag is placed at 28 bit! | ||
2722 | */ | ||
2723 | if ((res >> 28) == 0x01) | ||
2724 | alc880_lg_automute(codec); | ||
2725 | } | 2901 | } |
2726 | 2902 | ||
2727 | /* | 2903 | /* |
@@ -2795,30 +2971,18 @@ static struct hda_verb alc880_lg_lw_init_verbs[] = { | |||
2795 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | 2971 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, |
2796 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | 2972 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
2797 | /* jack sense */ | 2973 | /* jack sense */ |
2798 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | 0x1}, | 2974 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | ALC880_HP_EVENT}, |
2799 | { } | 2975 | { } |
2800 | }; | 2976 | }; |
2801 | 2977 | ||
2802 | /* toggle speaker-output according to the hp-jack state */ | 2978 | /* toggle speaker-output according to the hp-jack state */ |
2803 | static void alc880_lg_lw_automute(struct hda_codec *codec) | 2979 | static void alc880_lg_lw_init_hook(struct hda_codec *codec) |
2804 | { | 2980 | { |
2805 | unsigned int present; | 2981 | struct alc_spec *spec = codec->spec; |
2806 | unsigned char bits; | ||
2807 | 2982 | ||
2808 | present = snd_hda_codec_read(codec, 0x1b, 0, | 2983 | spec->autocfg.hp_pins[0] = 0x1b; |
2809 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 2984 | spec->autocfg.speaker_pins[0] = 0x14; |
2810 | bits = present ? HDA_AMP_MUTE : 0; | 2985 | alc_automute_amp(codec); |
2811 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
2812 | HDA_AMP_MUTE, bits); | ||
2813 | } | ||
2814 | |||
2815 | static void alc880_lg_lw_unsol_event(struct hda_codec *codec, unsigned int res) | ||
2816 | { | ||
2817 | /* Looks like the unsol event is incompatible with the standard | ||
2818 | * definition. 4bit tag is placed at 28 bit! | ||
2819 | */ | ||
2820 | if ((res >> 28) == 0x01) | ||
2821 | alc880_lg_lw_automute(codec); | ||
2822 | } | 2986 | } |
2823 | 2987 | ||
2824 | static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { | 2988 | static struct snd_kcontrol_new alc880_medion_rim_mixer[] = { |
@@ -2865,16 +3029,10 @@ static struct hda_verb alc880_medion_rim_init_verbs[] = { | |||
2865 | /* toggle speaker-output according to the hp-jack state */ | 3029 | /* toggle speaker-output according to the hp-jack state */ |
2866 | static void alc880_medion_rim_automute(struct hda_codec *codec) | 3030 | static void alc880_medion_rim_automute(struct hda_codec *codec) |
2867 | { | 3031 | { |
2868 | unsigned int present; | 3032 | struct alc_spec *spec = codec->spec; |
2869 | unsigned char bits; | 3033 | alc_automute_amp(codec); |
2870 | 3034 | /* toggle EAPD */ | |
2871 | present = snd_hda_codec_read(codec, 0x14, 0, | 3035 | if (spec->jack_present) |
2872 | AC_VERB_GET_PIN_SENSE, 0) | ||
2873 | & AC_PINSENSE_PRESENCE; | ||
2874 | bits = present ? HDA_AMP_MUTE : 0; | ||
2875 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
2876 | HDA_AMP_MUTE, bits); | ||
2877 | if (present) | ||
2878 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); | 3036 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0); |
2879 | else | 3037 | else |
2880 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); | 3038 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 2); |
@@ -2890,6 +3048,15 @@ static void alc880_medion_rim_unsol_event(struct hda_codec *codec, | |||
2890 | alc880_medion_rim_automute(codec); | 3048 | alc880_medion_rim_automute(codec); |
2891 | } | 3049 | } |
2892 | 3050 | ||
3051 | static void alc880_medion_rim_init_hook(struct hda_codec *codec) | ||
3052 | { | ||
3053 | struct alc_spec *spec = codec->spec; | ||
3054 | |||
3055 | spec->autocfg.hp_pins[0] = 0x14; | ||
3056 | spec->autocfg.speaker_pins[0] = 0x1b; | ||
3057 | alc880_medion_rim_automute(codec); | ||
3058 | } | ||
3059 | |||
2893 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 3060 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
2894 | static struct hda_amp_list alc880_loopbacks[] = { | 3061 | static struct hda_amp_list alc880_loopbacks[] = { |
2895 | { 0x0b, HDA_INPUT, 0 }, | 3062 | { 0x0b, HDA_INPUT, 0 }, |
@@ -2918,8 +3085,7 @@ static int alc_init(struct hda_codec *codec) | |||
2918 | unsigned int i; | 3085 | unsigned int i; |
2919 | 3086 | ||
2920 | alc_fix_pll(codec); | 3087 | alc_fix_pll(codec); |
2921 | if (codec->vendor_id == 0x10ec0888) | 3088 | alc_auto_init_amp(codec, spec->init_amp); |
2922 | alc888_coef_init(codec); | ||
2923 | 3089 | ||
2924 | for (i = 0; i < spec->num_init_verbs; i++) | 3090 | for (i = 0; i < spec->num_init_verbs; i++) |
2925 | snd_hda_sequence_write(codec, spec->init_verbs[i]); | 3091 | snd_hda_sequence_write(codec, spec->init_verbs[i]); |
@@ -3121,7 +3287,10 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
3121 | if (spec->no_analog) | 3287 | if (spec->no_analog) |
3122 | goto skip_analog; | 3288 | goto skip_analog; |
3123 | 3289 | ||
3290 | snprintf(spec->stream_name_analog, sizeof(spec->stream_name_analog), | ||
3291 | "%s Analog", codec->chip_name); | ||
3124 | info->name = spec->stream_name_analog; | 3292 | info->name = spec->stream_name_analog; |
3293 | |||
3125 | if (spec->stream_analog_playback) { | 3294 | if (spec->stream_analog_playback) { |
3126 | if (snd_BUG_ON(!spec->multiout.dac_nids)) | 3295 | if (snd_BUG_ON(!spec->multiout.dac_nids)) |
3127 | return -EINVAL; | 3296 | return -EINVAL; |
@@ -3147,6 +3316,9 @@ static int alc_build_pcms(struct hda_codec *codec) | |||
3147 | skip_analog: | 3316 | skip_analog: |
3148 | /* SPDIF for stream index #1 */ | 3317 | /* SPDIF for stream index #1 */ |
3149 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { | 3318 | if (spec->multiout.dig_out_nid || spec->dig_in_nid) { |
3319 | snprintf(spec->stream_name_digital, | ||
3320 | sizeof(spec->stream_name_digital), | ||
3321 | "%s Digital", codec->chip_name); | ||
3150 | codec->num_pcms = 2; | 3322 | codec->num_pcms = 2; |
3151 | codec->slave_dig_outs = spec->multiout.slave_dig_outs; | 3323 | codec->slave_dig_outs = spec->multiout.slave_dig_outs; |
3152 | info = spec->pcm_rec + 1; | 3324 | info = spec->pcm_rec + 1; |
@@ -3749,7 +3921,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
3749 | .channel_mode = alc880_2_jack_modes, | 3921 | .channel_mode = alc880_2_jack_modes, |
3750 | .input_mux = &alc880_f1734_capture_source, | 3922 | .input_mux = &alc880_f1734_capture_source, |
3751 | .unsol_event = alc880_uniwill_p53_unsol_event, | 3923 | .unsol_event = alc880_uniwill_p53_unsol_event, |
3752 | .init_hook = alc880_uniwill_p53_hp_automute, | 3924 | .init_hook = alc880_uniwill_p53_init_hook, |
3753 | }, | 3925 | }, |
3754 | [ALC880_ASUS] = { | 3926 | [ALC880_ASUS] = { |
3755 | .mixers = { alc880_asus_mixer }, | 3927 | .mixers = { alc880_asus_mixer }, |
@@ -3826,7 +3998,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
3826 | .need_dac_fix = 1, | 3998 | .need_dac_fix = 1, |
3827 | .input_mux = &alc880_capture_source, | 3999 | .input_mux = &alc880_capture_source, |
3828 | .unsol_event = alc880_uniwill_unsol_event, | 4000 | .unsol_event = alc880_uniwill_unsol_event, |
3829 | .init_hook = alc880_uniwill_automute, | 4001 | .init_hook = alc880_uniwill_init_hook, |
3830 | }, | 4002 | }, |
3831 | [ALC880_UNIWILL_P53] = { | 4003 | [ALC880_UNIWILL_P53] = { |
3832 | .mixers = { alc880_uniwill_p53_mixer }, | 4004 | .mixers = { alc880_uniwill_p53_mixer }, |
@@ -3838,7 +4010,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
3838 | .channel_mode = alc880_threestack_modes, | 4010 | .channel_mode = alc880_threestack_modes, |
3839 | .input_mux = &alc880_capture_source, | 4011 | .input_mux = &alc880_capture_source, |
3840 | .unsol_event = alc880_uniwill_p53_unsol_event, | 4012 | .unsol_event = alc880_uniwill_p53_unsol_event, |
3841 | .init_hook = alc880_uniwill_p53_hp_automute, | 4013 | .init_hook = alc880_uniwill_p53_init_hook, |
3842 | }, | 4014 | }, |
3843 | [ALC880_FUJITSU] = { | 4015 | [ALC880_FUJITSU] = { |
3844 | .mixers = { alc880_fujitsu_mixer }, | 4016 | .mixers = { alc880_fujitsu_mixer }, |
@@ -3852,7 +4024,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
3852 | .channel_mode = alc880_2_jack_modes, | 4024 | .channel_mode = alc880_2_jack_modes, |
3853 | .input_mux = &alc880_capture_source, | 4025 | .input_mux = &alc880_capture_source, |
3854 | .unsol_event = alc880_uniwill_p53_unsol_event, | 4026 | .unsol_event = alc880_uniwill_p53_unsol_event, |
3855 | .init_hook = alc880_uniwill_p53_hp_automute, | 4027 | .init_hook = alc880_uniwill_p53_init_hook, |
3856 | }, | 4028 | }, |
3857 | [ALC880_CLEVO] = { | 4029 | [ALC880_CLEVO] = { |
3858 | .mixers = { alc880_three_stack_mixer }, | 4030 | .mixers = { alc880_three_stack_mixer }, |
@@ -3877,8 +4049,8 @@ static struct alc_config_preset alc880_presets[] = { | |||
3877 | .channel_mode = alc880_lg_ch_modes, | 4049 | .channel_mode = alc880_lg_ch_modes, |
3878 | .need_dac_fix = 1, | 4050 | .need_dac_fix = 1, |
3879 | .input_mux = &alc880_lg_capture_source, | 4051 | .input_mux = &alc880_lg_capture_source, |
3880 | .unsol_event = alc880_lg_unsol_event, | 4052 | .unsol_event = alc_automute_amp_unsol_event, |
3881 | .init_hook = alc880_lg_automute, | 4053 | .init_hook = alc880_lg_init_hook, |
3882 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 4054 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
3883 | .loopbacks = alc880_lg_loopbacks, | 4055 | .loopbacks = alc880_lg_loopbacks, |
3884 | #endif | 4056 | #endif |
@@ -3893,8 +4065,8 @@ static struct alc_config_preset alc880_presets[] = { | |||
3893 | .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), | 4065 | .num_channel_mode = ARRAY_SIZE(alc880_lg_lw_modes), |
3894 | .channel_mode = alc880_lg_lw_modes, | 4066 | .channel_mode = alc880_lg_lw_modes, |
3895 | .input_mux = &alc880_lg_lw_capture_source, | 4067 | .input_mux = &alc880_lg_lw_capture_source, |
3896 | .unsol_event = alc880_lg_lw_unsol_event, | 4068 | .unsol_event = alc_automute_amp_unsol_event, |
3897 | .init_hook = alc880_lg_lw_automute, | 4069 | .init_hook = alc880_lg_lw_init_hook, |
3898 | }, | 4070 | }, |
3899 | [ALC880_MEDION_RIM] = { | 4071 | [ALC880_MEDION_RIM] = { |
3900 | .mixers = { alc880_medion_rim_mixer }, | 4072 | .mixers = { alc880_medion_rim_mixer }, |
@@ -3908,7 +4080,7 @@ static struct alc_config_preset alc880_presets[] = { | |||
3908 | .channel_mode = alc880_2_jack_modes, | 4080 | .channel_mode = alc880_2_jack_modes, |
3909 | .input_mux = &alc880_medion_rim_capture_source, | 4081 | .input_mux = &alc880_medion_rim_capture_source, |
3910 | .unsol_event = alc880_medion_rim_unsol_event, | 4082 | .unsol_event = alc880_medion_rim_unsol_event, |
3911 | .init_hook = alc880_medion_rim_automute, | 4083 | .init_hook = alc880_medion_rim_init_hook, |
3912 | }, | 4084 | }, |
3913 | #ifdef CONFIG_SND_DEBUG | 4085 | #ifdef CONFIG_SND_DEBUG |
3914 | [ALC880_TEST] = { | 4086 | [ALC880_TEST] = { |
@@ -4193,7 +4365,6 @@ static void alc880_auto_init_multi_out(struct hda_codec *codec) | |||
4193 | struct alc_spec *spec = codec->spec; | 4365 | struct alc_spec *spec = codec->spec; |
4194 | int i; | 4366 | int i; |
4195 | 4367 | ||
4196 | alc_subsystem_id(codec, 0x15, 0x1b, 0x14); | ||
4197 | for (i = 0; i < spec->autocfg.line_outs; i++) { | 4368 | for (i = 0; i < spec->autocfg.line_outs; i++) { |
4198 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 4369 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
4199 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 4370 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -4298,6 +4469,8 @@ static int alc880_parse_auto_config(struct hda_codec *codec) | |||
4298 | spec->num_mux_defs = 1; | 4469 | spec->num_mux_defs = 1; |
4299 | spec->input_mux = &spec->private_imux[0]; | 4470 | spec->input_mux = &spec->private_imux[0]; |
4300 | 4471 | ||
4472 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | ||
4473 | |||
4301 | return 1; | 4474 | return 1; |
4302 | } | 4475 | } |
4303 | 4476 | ||
@@ -4355,8 +4528,8 @@ static int patch_alc880(struct hda_codec *codec) | |||
4355 | alc880_models, | 4528 | alc880_models, |
4356 | alc880_cfg_tbl); | 4529 | alc880_cfg_tbl); |
4357 | if (board_config < 0) { | 4530 | if (board_config < 0) { |
4358 | printk(KERN_INFO "hda_codec: Unknown model for ALC880, " | 4531 | printk(KERN_INFO "hda_codec: Unknown model for %s, " |
4359 | "trying auto-probe from BIOS...\n"); | 4532 | "trying auto-probe from BIOS...\n", codec->chip_name); |
4360 | board_config = ALC880_AUTO; | 4533 | board_config = ALC880_AUTO; |
4361 | } | 4534 | } |
4362 | 4535 | ||
@@ -4383,12 +4556,10 @@ static int patch_alc880(struct hda_codec *codec) | |||
4383 | if (board_config != ALC880_AUTO) | 4556 | if (board_config != ALC880_AUTO) |
4384 | setup_preset(spec, &alc880_presets[board_config]); | 4557 | setup_preset(spec, &alc880_presets[board_config]); |
4385 | 4558 | ||
4386 | spec->stream_name_analog = "ALC880 Analog"; | ||
4387 | spec->stream_analog_playback = &alc880_pcm_analog_playback; | 4559 | spec->stream_analog_playback = &alc880_pcm_analog_playback; |
4388 | spec->stream_analog_capture = &alc880_pcm_analog_capture; | 4560 | spec->stream_analog_capture = &alc880_pcm_analog_capture; |
4389 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; | 4561 | spec->stream_analog_alt_capture = &alc880_pcm_analog_alt_capture; |
4390 | 4562 | ||
4391 | spec->stream_name_digital = "ALC880 Digital"; | ||
4392 | spec->stream_digital_playback = &alc880_pcm_digital_playback; | 4563 | spec->stream_digital_playback = &alc880_pcm_digital_playback; |
4393 | spec->stream_digital_capture = &alc880_pcm_digital_capture; | 4564 | spec->stream_digital_capture = &alc880_pcm_digital_capture; |
4394 | 4565 | ||
@@ -5673,7 +5844,6 @@ static void alc260_auto_init_multi_out(struct hda_codec *codec) | |||
5673 | struct alc_spec *spec = codec->spec; | 5844 | struct alc_spec *spec = codec->spec; |
5674 | hda_nid_t nid; | 5845 | hda_nid_t nid; |
5675 | 5846 | ||
5676 | alc_subsystem_id(codec, 0x10, 0x15, 0x0f); | ||
5677 | nid = spec->autocfg.line_out_pins[0]; | 5847 | nid = spec->autocfg.line_out_pins[0]; |
5678 | if (nid) { | 5848 | if (nid) { |
5679 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 5849 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -5783,6 +5953,8 @@ static int alc260_parse_auto_config(struct hda_codec *codec) | |||
5783 | spec->num_mux_defs = 1; | 5953 | spec->num_mux_defs = 1; |
5784 | spec->input_mux = &spec->private_imux[0]; | 5954 | spec->input_mux = &spec->private_imux[0]; |
5785 | 5955 | ||
5956 | alc_ssid_check(codec, 0x10, 0x15, 0x0f); | ||
5957 | |||
5786 | return 1; | 5958 | return 1; |
5787 | } | 5959 | } |
5788 | 5960 | ||
@@ -6000,8 +6172,9 @@ static int patch_alc260(struct hda_codec *codec) | |||
6000 | alc260_models, | 6172 | alc260_models, |
6001 | alc260_cfg_tbl); | 6173 | alc260_cfg_tbl); |
6002 | if (board_config < 0) { | 6174 | if (board_config < 0) { |
6003 | snd_printd(KERN_INFO "hda_codec: Unknown model for ALC260, " | 6175 | snd_printd(KERN_INFO "hda_codec: Unknown model for %s, " |
6004 | "trying auto-probe from BIOS...\n"); | 6176 | "trying auto-probe from BIOS...\n", |
6177 | codec->chip_name); | ||
6005 | board_config = ALC260_AUTO; | 6178 | board_config = ALC260_AUTO; |
6006 | } | 6179 | } |
6007 | 6180 | ||
@@ -6028,11 +6201,9 @@ static int patch_alc260(struct hda_codec *codec) | |||
6028 | if (board_config != ALC260_AUTO) | 6201 | if (board_config != ALC260_AUTO) |
6029 | setup_preset(spec, &alc260_presets[board_config]); | 6202 | setup_preset(spec, &alc260_presets[board_config]); |
6030 | 6203 | ||
6031 | spec->stream_name_analog = "ALC260 Analog"; | ||
6032 | spec->stream_analog_playback = &alc260_pcm_analog_playback; | 6204 | spec->stream_analog_playback = &alc260_pcm_analog_playback; |
6033 | spec->stream_analog_capture = &alc260_pcm_analog_capture; | 6205 | spec->stream_analog_capture = &alc260_pcm_analog_capture; |
6034 | 6206 | ||
6035 | spec->stream_name_digital = "ALC260 Digital"; | ||
6036 | spec->stream_digital_playback = &alc260_pcm_digital_playback; | 6207 | spec->stream_digital_playback = &alc260_pcm_digital_playback; |
6037 | spec->stream_digital_capture = &alc260_pcm_digital_capture; | 6208 | spec->stream_digital_capture = &alc260_pcm_digital_capture; |
6038 | 6209 | ||
@@ -6109,6 +6280,16 @@ static struct hda_input_mux alc882_capture_source = { | |||
6109 | { "CD", 0x4 }, | 6280 | { "CD", 0x4 }, |
6110 | }, | 6281 | }, |
6111 | }; | 6282 | }; |
6283 | |||
6284 | static struct hda_input_mux mb5_capture_source = { | ||
6285 | .num_items = 3, | ||
6286 | .items = { | ||
6287 | { "Mic", 0x1 }, | ||
6288 | { "Line", 0x2 }, | ||
6289 | { "CD", 0x4 }, | ||
6290 | }, | ||
6291 | }; | ||
6292 | |||
6112 | /* | 6293 | /* |
6113 | * 2ch mode | 6294 | * 2ch mode |
6114 | */ | 6295 | */ |
@@ -6196,6 +6377,34 @@ static struct hda_channel_mode alc885_mbp_6ch_modes[2] = { | |||
6196 | { 6, alc885_mbp_ch6_init }, | 6377 | { 6, alc885_mbp_ch6_init }, |
6197 | }; | 6378 | }; |
6198 | 6379 | ||
6380 | /* | ||
6381 | * 2ch | ||
6382 | * Speakers/Woofer/HP = Front | ||
6383 | * LineIn = Input | ||
6384 | */ | ||
6385 | static struct hda_verb alc885_mb5_ch2_init[] = { | ||
6386 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
6387 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
6388 | { } /* end */ | ||
6389 | }; | ||
6390 | |||
6391 | /* | ||
6392 | * 6ch mode | ||
6393 | * Speakers/HP = Front | ||
6394 | * Woofer = LFE | ||
6395 | * LineIn = Surround | ||
6396 | */ | ||
6397 | static struct hda_verb alc885_mb5_ch6_init[] = { | ||
6398 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
6399 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6400 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
6401 | { } /* end */ | ||
6402 | }; | ||
6403 | |||
6404 | static struct hda_channel_mode alc885_mb5_6ch_modes[2] = { | ||
6405 | { 2, alc885_mb5_ch2_init }, | ||
6406 | { 6, alc885_mb5_ch6_init }, | ||
6407 | }; | ||
6199 | 6408 | ||
6200 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 | 6409 | /* Pin assignment: Front=0x14, Rear=0x15, CLFE=0x16, Side=0x17 |
6201 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b | 6410 | * Mic=0x18, Front Mic=0x19, Line-In=0x1a, HP=0x1b |
@@ -6238,6 +6447,25 @@ static struct snd_kcontrol_new alc885_mbp3_mixer[] = { | |||
6238 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), | 6447 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), |
6239 | { } /* end */ | 6448 | { } /* end */ |
6240 | }; | 6449 | }; |
6450 | |||
6451 | static struct snd_kcontrol_new alc885_mb5_mixer[] = { | ||
6452 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), | ||
6453 | HDA_BIND_MUTE ("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), | ||
6454 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), | ||
6455 | HDA_BIND_MUTE ("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), | ||
6456 | HDA_CODEC_VOLUME("LFE Playback Volume", 0x0e, 0x00, HDA_OUTPUT), | ||
6457 | HDA_BIND_MUTE ("LFE Playback Switch", 0x0e, 0x02, HDA_INPUT), | ||
6458 | HDA_CODEC_VOLUME("HP Playback Volume", 0x0f, 0x00, HDA_OUTPUT), | ||
6459 | HDA_BIND_MUTE ("HP Playback Switch", 0x0f, 0x02, HDA_INPUT), | ||
6460 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
6461 | HDA_CODEC_MUTE ("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
6462 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
6463 | HDA_CODEC_MUTE ("Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
6464 | HDA_CODEC_VOLUME("Line Boost", 0x15, 0x00, HDA_INPUT), | ||
6465 | HDA_CODEC_VOLUME("Mic Boost", 0x19, 0x00, HDA_INPUT), | ||
6466 | { } /* end */ | ||
6467 | }; | ||
6468 | |||
6241 | static struct snd_kcontrol_new alc882_w2jc_mixer[] = { | 6469 | static struct snd_kcontrol_new alc882_w2jc_mixer[] = { |
6242 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 6470 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
6243 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | 6471 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), |
@@ -6465,6 +6693,55 @@ static struct hda_verb alc882_macpro_init_verbs[] = { | |||
6465 | { } | 6693 | { } |
6466 | }; | 6694 | }; |
6467 | 6695 | ||
6696 | /* Macbook 5,1 */ | ||
6697 | static struct hda_verb alc885_mb5_init_verbs[] = { | ||
6698 | /* DACs */ | ||
6699 | {0x02, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6700 | {0x03, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6701 | {0x04, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6702 | {0x05, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6703 | /* Front mixer */ | ||
6704 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
6705 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
6706 | {0x0c, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
6707 | /* Surround mixer */ | ||
6708 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
6709 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
6710 | {0x0d, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
6711 | /* LFE mixer */ | ||
6712 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
6713 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
6714 | {0x0e, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
6715 | /* HP mixer */ | ||
6716 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_ZERO}, | ||
6717 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(0)}, | ||
6718 | {0x0f, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(1)}, | ||
6719 | /* Front Pin (0x0c) */ | ||
6720 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, | ||
6721 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6722 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
6723 | /* LFE Pin (0x0e) */ | ||
6724 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT | 0x01}, | ||
6725 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6726 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
6727 | /* HP Pin (0x0f) */ | ||
6728 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
6729 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
6730 | {0x14, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
6731 | /* Front Mic pin: input vref at 80% */ | ||
6732 | {0x19, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80}, | ||
6733 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
6734 | /* Line In pin */ | ||
6735 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, | ||
6736 | {0x15, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, | ||
6737 | |||
6738 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_UNMUTE(1)}, | ||
6739 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(3)}, | ||
6740 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(2)}, | ||
6741 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, AMP_IN_MUTE(4)}, | ||
6742 | { } | ||
6743 | }; | ||
6744 | |||
6468 | /* Macbook Pro rev3 */ | 6745 | /* Macbook Pro rev3 */ |
6469 | static struct hda_verb alc885_mbp3_init_verbs[] = { | 6746 | static struct hda_verb alc885_mbp3_init_verbs[] = { |
6470 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ | 6747 | /* Front mixer: unmute input/output amp left and right (volume = 0) */ |
@@ -6554,45 +6831,23 @@ static struct hda_verb alc885_imac24_init_verbs[] = { | |||
6554 | }; | 6831 | }; |
6555 | 6832 | ||
6556 | /* Toggle speaker-output according to the hp-jack state */ | 6833 | /* Toggle speaker-output according to the hp-jack state */ |
6557 | static void alc885_imac24_automute(struct hda_codec *codec) | 6834 | static void alc885_imac24_automute_init_hook(struct hda_codec *codec) |
6558 | { | 6835 | { |
6559 | unsigned int present; | 6836 | struct alc_spec *spec = codec->spec; |
6560 | |||
6561 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
6562 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
6563 | snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, | ||
6564 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
6565 | snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, | ||
6566 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
6567 | } | ||
6568 | 6837 | ||
6569 | /* Processes unsolicited events. */ | 6838 | spec->autocfg.hp_pins[0] = 0x14; |
6570 | static void alc885_imac24_unsol_event(struct hda_codec *codec, | 6839 | spec->autocfg.speaker_pins[0] = 0x18; |
6571 | unsigned int res) | 6840 | spec->autocfg.speaker_pins[1] = 0x1a; |
6572 | { | 6841 | alc_automute_amp(codec); |
6573 | /* Headphone insertion or removal. */ | ||
6574 | if ((res >> 26) == ALC880_HP_EVENT) | ||
6575 | alc885_imac24_automute(codec); | ||
6576 | } | 6842 | } |
6577 | 6843 | ||
6578 | static void alc885_mbp3_automute(struct hda_codec *codec) | 6844 | static void alc885_mbp3_init_hook(struct hda_codec *codec) |
6579 | { | 6845 | { |
6580 | unsigned int present; | 6846 | struct alc_spec *spec = codec->spec; |
6581 | |||
6582 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
6583 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
6584 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
6585 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
6586 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
6587 | HDA_AMP_MUTE, present ? 0 : HDA_AMP_MUTE); | ||
6588 | 6847 | ||
6589 | } | 6848 | spec->autocfg.hp_pins[0] = 0x15; |
6590 | static void alc885_mbp3_unsol_event(struct hda_codec *codec, | 6849 | spec->autocfg.speaker_pins[0] = 0x14; |
6591 | unsigned int res) | 6850 | alc_automute_amp(codec); |
6592 | { | ||
6593 | /* Headphone insertion or removal. */ | ||
6594 | if ((res >> 26) == ALC880_HP_EVENT) | ||
6595 | alc885_mbp3_automute(codec); | ||
6596 | } | 6851 | } |
6597 | 6852 | ||
6598 | 6853 | ||
@@ -6617,24 +6872,25 @@ static struct hda_verb alc882_targa_verbs[] = { | |||
6617 | /* toggle speaker-output according to the hp-jack state */ | 6872 | /* toggle speaker-output according to the hp-jack state */ |
6618 | static void alc882_targa_automute(struct hda_codec *codec) | 6873 | static void alc882_targa_automute(struct hda_codec *codec) |
6619 | { | 6874 | { |
6620 | unsigned int present; | 6875 | struct alc_spec *spec = codec->spec; |
6621 | 6876 | alc_automute_amp(codec); | |
6622 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
6623 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
6624 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
6625 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
6626 | snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, | 6877 | snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, |
6627 | present ? 1 : 3); | 6878 | spec->jack_present ? 1 : 3); |
6879 | } | ||
6880 | |||
6881 | static void alc882_targa_init_hook(struct hda_codec *codec) | ||
6882 | { | ||
6883 | struct alc_spec *spec = codec->spec; | ||
6884 | |||
6885 | spec->autocfg.hp_pins[0] = 0x14; | ||
6886 | spec->autocfg.speaker_pins[0] = 0x1b; | ||
6887 | alc882_targa_automute(codec); | ||
6628 | } | 6888 | } |
6629 | 6889 | ||
6630 | static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) | 6890 | static void alc882_targa_unsol_event(struct hda_codec *codec, unsigned int res) |
6631 | { | 6891 | { |
6632 | /* Looks like the unsol event is incompatible with the standard | 6892 | if ((res >> 26) == ALC880_HP_EVENT) |
6633 | * definition. 4bit tag is placed at 26 bit! | ||
6634 | */ | ||
6635 | if (((res >> 26) == ALC880_HP_EVENT)) { | ||
6636 | alc882_targa_automute(codec); | 6893 | alc882_targa_automute(codec); |
6637 | } | ||
6638 | } | 6894 | } |
6639 | 6895 | ||
6640 | static struct hda_verb alc882_asus_a7j_verbs[] = { | 6896 | static struct hda_verb alc882_asus_a7j_verbs[] = { |
@@ -6716,7 +6972,7 @@ static void alc885_macpro_init_hook(struct hda_codec *codec) | |||
6716 | static void alc885_imac24_init_hook(struct hda_codec *codec) | 6972 | static void alc885_imac24_init_hook(struct hda_codec *codec) |
6717 | { | 6973 | { |
6718 | alc885_macpro_init_hook(codec); | 6974 | alc885_macpro_init_hook(codec); |
6719 | alc885_imac24_automute(codec); | 6975 | alc885_imac24_automute_init_hook(codec); |
6720 | } | 6976 | } |
6721 | 6977 | ||
6722 | /* | 6978 | /* |
@@ -6809,6 +7065,7 @@ static const char *alc882_models[ALC882_MODEL_LAST] = { | |||
6809 | [ALC882_ASUS_A7J] = "asus-a7j", | 7065 | [ALC882_ASUS_A7J] = "asus-a7j", |
6810 | [ALC882_ASUS_A7M] = "asus-a7m", | 7066 | [ALC882_ASUS_A7M] = "asus-a7m", |
6811 | [ALC885_MACPRO] = "macpro", | 7067 | [ALC885_MACPRO] = "macpro", |
7068 | [ALC885_MB5] = "mb5", | ||
6812 | [ALC885_MBP3] = "mbp3", | 7069 | [ALC885_MBP3] = "mbp3", |
6813 | [ALC885_IMAC24] = "imac24", | 7070 | [ALC885_IMAC24] = "imac24", |
6814 | [ALC882_AUTO] = "auto", | 7071 | [ALC882_AUTO] = "auto", |
@@ -6886,8 +7143,20 @@ static struct alc_config_preset alc882_presets[] = { | |||
6886 | .input_mux = &alc882_capture_source, | 7143 | .input_mux = &alc882_capture_source, |
6887 | .dig_out_nid = ALC882_DIGOUT_NID, | 7144 | .dig_out_nid = ALC882_DIGOUT_NID, |
6888 | .dig_in_nid = ALC882_DIGIN_NID, | 7145 | .dig_in_nid = ALC882_DIGIN_NID, |
6889 | .unsol_event = alc885_mbp3_unsol_event, | 7146 | .unsol_event = alc_automute_amp_unsol_event, |
6890 | .init_hook = alc885_mbp3_automute, | 7147 | .init_hook = alc885_mbp3_init_hook, |
7148 | }, | ||
7149 | [ALC885_MB5] = { | ||
7150 | .mixers = { alc885_mb5_mixer, alc882_chmode_mixer }, | ||
7151 | .init_verbs = { alc885_mb5_init_verbs, | ||
7152 | alc880_gpio1_init_verbs }, | ||
7153 | .num_dacs = ARRAY_SIZE(alc882_dac_nids), | ||
7154 | .dac_nids = alc882_dac_nids, | ||
7155 | .channel_mode = alc885_mb5_6ch_modes, | ||
7156 | .num_channel_mode = ARRAY_SIZE(alc885_mb5_6ch_modes), | ||
7157 | .input_mux = &mb5_capture_source, | ||
7158 | .dig_out_nid = ALC882_DIGOUT_NID, | ||
7159 | .dig_in_nid = ALC882_DIGIN_NID, | ||
6891 | }, | 7160 | }, |
6892 | [ALC885_MACPRO] = { | 7161 | [ALC885_MACPRO] = { |
6893 | .mixers = { alc882_macpro_mixer }, | 7162 | .mixers = { alc882_macpro_mixer }, |
@@ -6911,7 +7180,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
6911 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), | 7180 | .num_channel_mode = ARRAY_SIZE(alc882_ch_modes), |
6912 | .channel_mode = alc882_ch_modes, | 7181 | .channel_mode = alc882_ch_modes, |
6913 | .input_mux = &alc882_capture_source, | 7182 | .input_mux = &alc882_capture_source, |
6914 | .unsol_event = alc885_imac24_unsol_event, | 7183 | .unsol_event = alc_automute_amp_unsol_event, |
6915 | .init_hook = alc885_imac24_init_hook, | 7184 | .init_hook = alc885_imac24_init_hook, |
6916 | }, | 7185 | }, |
6917 | [ALC882_TARGA] = { | 7186 | [ALC882_TARGA] = { |
@@ -6928,7 +7197,7 @@ static struct alc_config_preset alc882_presets[] = { | |||
6928 | .need_dac_fix = 1, | 7197 | .need_dac_fix = 1, |
6929 | .input_mux = &alc882_capture_source, | 7198 | .input_mux = &alc882_capture_source, |
6930 | .unsol_event = alc882_targa_unsol_event, | 7199 | .unsol_event = alc882_targa_unsol_event, |
6931 | .init_hook = alc882_targa_automute, | 7200 | .init_hook = alc882_targa_init_hook, |
6932 | }, | 7201 | }, |
6933 | [ALC882_ASUS_A7J] = { | 7202 | [ALC882_ASUS_A7J] = { |
6934 | .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, | 7203 | .mixers = { alc882_asus_a7j_mixer, alc882_chmode_mixer }, |
@@ -7008,7 +7277,6 @@ static void alc882_auto_init_multi_out(struct hda_codec *codec) | |||
7008 | struct alc_spec *spec = codec->spec; | 7277 | struct alc_spec *spec = codec->spec; |
7009 | int i; | 7278 | int i; |
7010 | 7279 | ||
7011 | alc_subsystem_id(codec, 0x15, 0x1b, 0x14); | ||
7012 | for (i = 0; i <= HDA_SIDE; i++) { | 7280 | for (i = 0; i <= HDA_SIDE; i++) { |
7013 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 7281 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
7014 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 7282 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -7191,10 +7459,17 @@ static int patch_alc882(struct hda_codec *codec) | |||
7191 | case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ | 7459 | case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */ |
7192 | case 0x106b00a4: /* MacbookPro4,1 */ | 7460 | case 0x106b00a4: /* MacbookPro4,1 */ |
7193 | case 0x106b2c00: /* Macbook Pro rev3 */ | 7461 | case 0x106b2c00: /* Macbook Pro rev3 */ |
7194 | case 0x106b3600: /* Macbook 3.1 */ | 7462 | /* Macbook 3.1 (0x106b3600) is handled by patch_alc883() */ |
7195 | case 0x106b3800: /* MacbookPro4,1 - latter revision */ | 7463 | case 0x106b3800: /* MacbookPro4,1 - latter revision */ |
7196 | board_config = ALC885_MBP3; | 7464 | board_config = ALC885_MBP3; |
7197 | break; | 7465 | break; |
7466 | case 0x106b3f00: /* Macbook 5,1 */ | ||
7467 | case 0x106b4000: /* Macbook Pro 5,1 - FIXME: HP jack sense | ||
7468 | * seems not working, so apparently | ||
7469 | * no perfect solution yet | ||
7470 | */ | ||
7471 | board_config = ALC885_MB5; | ||
7472 | break; | ||
7198 | default: | 7473 | default: |
7199 | /* ALC889A is handled better as ALC888-compatible */ | 7474 | /* ALC889A is handled better as ALC888-compatible */ |
7200 | if (codec->revision_id == 0x100101 || | 7475 | if (codec->revision_id == 0x100101 || |
@@ -7202,8 +7477,9 @@ static int patch_alc882(struct hda_codec *codec) | |||
7202 | alc_free(codec); | 7477 | alc_free(codec); |
7203 | return patch_alc883(codec); | 7478 | return patch_alc883(codec); |
7204 | } | 7479 | } |
7205 | printk(KERN_INFO "hda_codec: Unknown model for ALC882, " | 7480 | printk(KERN_INFO "hda_codec: Unknown model for %s, " |
7206 | "trying auto-probe from BIOS...\n"); | 7481 | "trying auto-probe from BIOS...\n", |
7482 | codec->chip_name); | ||
7207 | board_config = ALC882_AUTO; | 7483 | board_config = ALC882_AUTO; |
7208 | } | 7484 | } |
7209 | } | 7485 | } |
@@ -7233,14 +7509,6 @@ static int patch_alc882(struct hda_codec *codec) | |||
7233 | if (board_config != ALC882_AUTO) | 7509 | if (board_config != ALC882_AUTO) |
7234 | setup_preset(spec, &alc882_presets[board_config]); | 7510 | setup_preset(spec, &alc882_presets[board_config]); |
7235 | 7511 | ||
7236 | if (codec->vendor_id == 0x10ec0885) { | ||
7237 | spec->stream_name_analog = "ALC885 Analog"; | ||
7238 | spec->stream_name_digital = "ALC885 Digital"; | ||
7239 | } else { | ||
7240 | spec->stream_name_analog = "ALC882 Analog"; | ||
7241 | spec->stream_name_digital = "ALC882 Digital"; | ||
7242 | } | ||
7243 | |||
7244 | spec->stream_analog_playback = &alc882_pcm_analog_playback; | 7512 | spec->stream_analog_playback = &alc882_pcm_analog_playback; |
7245 | spec->stream_analog_capture = &alc882_pcm_analog_capture; | 7513 | spec->stream_analog_capture = &alc882_pcm_analog_capture; |
7246 | /* FIXME: setup DAC5 */ | 7514 | /* FIXME: setup DAC5 */ |
@@ -7393,6 +7661,17 @@ static struct hda_input_mux alc883_asus_eee1601_capture_source = { | |||
7393 | }, | 7661 | }, |
7394 | }; | 7662 | }; |
7395 | 7663 | ||
7664 | static struct hda_input_mux alc889A_mb31_capture_source = { | ||
7665 | .num_items = 2, | ||
7666 | .items = { | ||
7667 | { "Mic", 0x0 }, | ||
7668 | /* Front Mic (0x01) unused */ | ||
7669 | { "Line", 0x2 }, | ||
7670 | /* Line 2 (0x03) unused */ | ||
7671 | /* CD (0x04) unsused? */ | ||
7672 | }, | ||
7673 | }; | ||
7674 | |||
7396 | /* | 7675 | /* |
7397 | * 2ch mode | 7676 | * 2ch mode |
7398 | */ | 7677 | */ |
@@ -7442,6 +7721,73 @@ static struct hda_channel_mode alc883_3ST_6ch_modes[3] = { | |||
7442 | { 6, alc883_3ST_ch6_init }, | 7721 | { 6, alc883_3ST_ch6_init }, |
7443 | }; | 7722 | }; |
7444 | 7723 | ||
7724 | |||
7725 | /* | ||
7726 | * 2ch mode | ||
7727 | */ | ||
7728 | static struct hda_verb alc883_4ST_ch2_init[] = { | ||
7729 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7730 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7731 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
7732 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
7733 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN }, | ||
7734 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
7735 | { } /* end */ | ||
7736 | }; | ||
7737 | |||
7738 | /* | ||
7739 | * 4ch mode | ||
7740 | */ | ||
7741 | static struct hda_verb alc883_4ST_ch4_init[] = { | ||
7742 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7743 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7744 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_VREF80 }, | ||
7745 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE }, | ||
7746 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7747 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7748 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
7749 | { } /* end */ | ||
7750 | }; | ||
7751 | |||
7752 | /* | ||
7753 | * 6ch mode | ||
7754 | */ | ||
7755 | static struct hda_verb alc883_4ST_ch6_init[] = { | ||
7756 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7757 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7758 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7759 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7760 | { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, | ||
7761 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7762 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7763 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
7764 | { } /* end */ | ||
7765 | }; | ||
7766 | |||
7767 | /* | ||
7768 | * 8ch mode | ||
7769 | */ | ||
7770 | static struct hda_verb alc883_4ST_ch8_init[] = { | ||
7771 | { 0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7772 | { 0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7773 | { 0x17, AC_VERB_SET_CONNECT_SEL, 0x03 }, | ||
7774 | { 0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7775 | { 0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7776 | { 0x18, AC_VERB_SET_CONNECT_SEL, 0x02 }, | ||
7777 | { 0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT }, | ||
7778 | { 0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE }, | ||
7779 | { 0x1a, AC_VERB_SET_CONNECT_SEL, 0x01 }, | ||
7780 | { } /* end */ | ||
7781 | }; | ||
7782 | |||
7783 | static struct hda_channel_mode alc883_4ST_8ch_modes[4] = { | ||
7784 | { 2, alc883_4ST_ch2_init }, | ||
7785 | { 4, alc883_4ST_ch4_init }, | ||
7786 | { 6, alc883_4ST_ch6_init }, | ||
7787 | { 8, alc883_4ST_ch8_init }, | ||
7788 | }; | ||
7789 | |||
7790 | |||
7445 | /* | 7791 | /* |
7446 | * 2ch mode | 7792 | * 2ch mode |
7447 | */ | 7793 | */ |
@@ -7511,6 +7857,49 @@ static struct hda_channel_mode alc883_sixstack_modes[2] = { | |||
7511 | { 8, alc883_sixstack_ch8_init }, | 7857 | { 8, alc883_sixstack_ch8_init }, |
7512 | }; | 7858 | }; |
7513 | 7859 | ||
7860 | /* 2ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:front) */ | ||
7861 | static struct hda_verb alc889A_mb31_ch2_init[] = { | ||
7862 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ | ||
7863 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ | ||
7864 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ | ||
7865 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ | ||
7866 | { } /* end */ | ||
7867 | }; | ||
7868 | |||
7869 | /* 4ch mode (Speaker:front, Subwoofer:CLFE, Line:CLFE, Headphones:front) */ | ||
7870 | static struct hda_verb alc889A_mb31_ch4_init[] = { | ||
7871 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP as front */ | ||
7872 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ | ||
7873 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ | ||
7874 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ | ||
7875 | { } /* end */ | ||
7876 | }; | ||
7877 | |||
7878 | /* 5ch mode (Speaker:front, Subwoofer:CLFE, Line:input, Headphones:rear) */ | ||
7879 | static struct hda_verb alc889A_mb31_ch5_init[] = { | ||
7880 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as rear */ | ||
7881 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Subwoofer on */ | ||
7882 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Line as input */ | ||
7883 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Line off */ | ||
7884 | { } /* end */ | ||
7885 | }; | ||
7886 | |||
7887 | /* 6ch mode (Speaker:front, Subwoofer:off, Line:CLFE, Headphones:Rear) */ | ||
7888 | static struct hda_verb alc889A_mb31_ch6_init[] = { | ||
7889 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x01}, /* HP as front */ | ||
7890 | {0x16, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Subwoofer off */ | ||
7891 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, /* Line as output */ | ||
7892 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, /* Line on */ | ||
7893 | { } /* end */ | ||
7894 | }; | ||
7895 | |||
7896 | static struct hda_channel_mode alc889A_mb31_6ch_modes[4] = { | ||
7897 | { 2, alc889A_mb31_ch2_init }, | ||
7898 | { 4, alc889A_mb31_ch4_init }, | ||
7899 | { 5, alc889A_mb31_ch5_init }, | ||
7900 | { 6, alc889A_mb31_ch6_init }, | ||
7901 | }; | ||
7902 | |||
7514 | static struct hda_verb alc883_medion_eapd_verbs[] = { | 7903 | static struct hda_verb alc883_medion_eapd_verbs[] = { |
7515 | /* eanable EAPD on medion laptop */ | 7904 | /* eanable EAPD on medion laptop */ |
7516 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, | 7905 | {0x20, AC_VERB_SET_COEF_INDEX, 0x07}, |
@@ -7776,8 +8165,6 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { | |||
7776 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), | 8165 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0d, 2, 2, HDA_INPUT), |
7777 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), | 8166 | HDA_CODEC_VOLUME("Side Playback Volume", 0x0f, 0x0, HDA_OUTPUT), |
7778 | HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), | 8167 | HDA_BIND_MUTE("Side Playback Switch", 0x0f, 2, HDA_INPUT), |
7779 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
7780 | HDA_CODEC_MUTE("iSpeaker Playback Switch", 0x1a, 0x0, HDA_OUTPUT), | ||
7781 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | 8168 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), |
7782 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | 8169 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), |
7783 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 8170 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
@@ -7791,6 +8178,42 @@ static struct snd_kcontrol_new alc888_lenovo_sky_mixer[] = { | |||
7791 | { } /* end */ | 8178 | { } /* end */ |
7792 | }; | 8179 | }; |
7793 | 8180 | ||
8181 | static struct snd_kcontrol_new alc889A_mb31_mixer[] = { | ||
8182 | /* Output mixers */ | ||
8183 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x00, HDA_OUTPUT), | ||
8184 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 0x02, HDA_INPUT), | ||
8185 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x0d, 0x00, HDA_OUTPUT), | ||
8186 | HDA_BIND_MUTE("Surround Playback Switch", 0x0d, 0x02, HDA_INPUT), | ||
8187 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x0e, 1, 0x00, | ||
8188 | HDA_OUTPUT), | ||
8189 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x0e, 1, 0x02, HDA_INPUT), | ||
8190 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x0e, 2, 0x00, HDA_OUTPUT), | ||
8191 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x0e, 2, 0x02, HDA_INPUT), | ||
8192 | /* Output switches */ | ||
8193 | HDA_CODEC_MUTE("Enable Speaker", 0x14, 0x00, HDA_OUTPUT), | ||
8194 | HDA_CODEC_MUTE("Enable Headphones", 0x15, 0x00, HDA_OUTPUT), | ||
8195 | HDA_CODEC_MUTE_MONO("Enable LFE", 0x16, 2, 0x00, HDA_OUTPUT), | ||
8196 | /* Boost mixers */ | ||
8197 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0x00, HDA_INPUT), | ||
8198 | HDA_CODEC_VOLUME("Line Boost", 0x1a, 0x00, HDA_INPUT), | ||
8199 | /* Input mixers */ | ||
8200 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x00, HDA_INPUT), | ||
8201 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x00, HDA_INPUT), | ||
8202 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
8203 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
8204 | { } /* end */ | ||
8205 | }; | ||
8206 | |||
8207 | static struct snd_kcontrol_new alc883_vaiott_mixer[] = { | ||
8208 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
8209 | HDA_BIND_MUTE("Front Playback Switch", 0x0c, 2, HDA_INPUT), | ||
8210 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | ||
8211 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
8212 | HDA_CODEC_VOLUME("Mic Boost", 0x19, 0, HDA_INPUT), | ||
8213 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
8214 | { } /* end */ | ||
8215 | }; | ||
8216 | |||
7794 | static struct hda_bind_ctls alc883_bind_cap_vol = { | 8217 | static struct hda_bind_ctls alc883_bind_cap_vol = { |
7795 | .ops = &snd_hda_bind_vol, | 8218 | .ops = &snd_hda_bind_vol, |
7796 | .values = { | 8219 | .values = { |
@@ -7926,16 +8349,14 @@ static struct hda_verb alc883_init_verbs[] = { | |||
7926 | }; | 8349 | }; |
7927 | 8350 | ||
7928 | /* toggle speaker-output according to the hp-jack state */ | 8351 | /* toggle speaker-output according to the hp-jack state */ |
7929 | static void alc883_mitac_hp_automute(struct hda_codec *codec) | 8352 | static void alc883_mitac_init_hook(struct hda_codec *codec) |
7930 | { | 8353 | { |
7931 | unsigned int present; | 8354 | struct alc_spec *spec = codec->spec; |
7932 | 8355 | ||
7933 | present = snd_hda_codec_read(codec, 0x15, 0, | 8356 | spec->autocfg.hp_pins[0] = 0x15; |
7934 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 8357 | spec->autocfg.speaker_pins[0] = 0x14; |
7935 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | 8358 | spec->autocfg.speaker_pins[1] = 0x17; |
7936 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 8359 | alc_automute_amp(codec); |
7937 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
7938 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
7939 | } | 8360 | } |
7940 | 8361 | ||
7941 | /* auto-toggle front mic */ | 8362 | /* auto-toggle front mic */ |
@@ -7952,25 +8373,6 @@ static void alc883_mitac_mic_automute(struct hda_codec *codec) | |||
7952 | } | 8373 | } |
7953 | */ | 8374 | */ |
7954 | 8375 | ||
7955 | static void alc883_mitac_automute(struct hda_codec *codec) | ||
7956 | { | ||
7957 | alc883_mitac_hp_automute(codec); | ||
7958 | /* alc883_mitac_mic_automute(codec); */ | ||
7959 | } | ||
7960 | |||
7961 | static void alc883_mitac_unsol_event(struct hda_codec *codec, | ||
7962 | unsigned int res) | ||
7963 | { | ||
7964 | switch (res >> 26) { | ||
7965 | case ALC880_HP_EVENT: | ||
7966 | alc883_mitac_hp_automute(codec); | ||
7967 | break; | ||
7968 | case ALC880_MIC_EVENT: | ||
7969 | /* alc883_mitac_mic_automute(codec); */ | ||
7970 | break; | ||
7971 | } | ||
7972 | } | ||
7973 | |||
7974 | static struct hda_verb alc883_mitac_verbs[] = { | 8376 | static struct hda_verb alc883_mitac_verbs[] = { |
7975 | /* HP */ | 8377 | /* HP */ |
7976 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, | 8378 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, |
@@ -8022,14 +8424,24 @@ static struct hda_verb alc883_tagra_verbs[] = { | |||
8022 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | 8424 | {0x14, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, |
8023 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | 8425 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
8024 | 8426 | ||
8025 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, /* mic/clfe */ | 8427 | /* Connect Line-Out side jack (SPDIF) to Side */ |
8026 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, /* line/surround */ | 8428 | {0x17, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, |
8027 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, /* HP */ | 8429 | {0x17, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, |
8430 | {0x17, AC_VERB_SET_CONNECT_SEL, 0x03}, | ||
8431 | /* Connect Mic jack to CLFE */ | ||
8432 | {0x18, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8433 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8434 | {0x18, AC_VERB_SET_CONNECT_SEL, 0x02}, | ||
8435 | /* Connect Line-in jack to Surround */ | ||
8436 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8437 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8438 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x01}, | ||
8439 | /* Connect HP out jack to Front */ | ||
8440 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT}, | ||
8441 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE}, | ||
8442 | {0x1b, AC_VERB_SET_CONNECT_SEL, 0x00}, | ||
8028 | 8443 | ||
8029 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | 8444 | {0x14, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, |
8030 | {0x01, AC_VERB_SET_GPIO_MASK, 0x03}, | ||
8031 | {0x01, AC_VERB_SET_GPIO_DIRECTION, 0x03}, | ||
8032 | {0x01, AC_VERB_SET_GPIO_DATA, 0x03}, | ||
8033 | 8445 | ||
8034 | { } /* end */ | 8446 | { } /* end */ |
8035 | }; | 8447 | }; |
@@ -8088,29 +8500,26 @@ static struct hda_verb alc888_6st_dell_verbs[] = { | |||
8088 | { } | 8500 | { } |
8089 | }; | 8501 | }; |
8090 | 8502 | ||
8091 | static void alc888_3st_hp_front_automute(struct hda_codec *codec) | 8503 | static struct hda_verb alc883_vaiott_verbs[] = { |
8092 | { | 8504 | /* HP */ |
8093 | unsigned int present, bits; | 8505 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, |
8506 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP}, | ||
8094 | 8507 | ||
8095 | present = snd_hda_codec_read(codec, 0x1b, 0, | 8508 | /* enable unsolicited event */ |
8096 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 8509 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, |
8097 | bits = present ? HDA_AMP_MUTE : 0; | 8510 | |
8098 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | 8511 | { } /* end */ |
8099 | HDA_AMP_MUTE, bits); | 8512 | }; |
8100 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
8101 | HDA_AMP_MUTE, bits); | ||
8102 | snd_hda_codec_amp_stereo(codec, 0x18, HDA_OUTPUT, 0, | ||
8103 | HDA_AMP_MUTE, bits); | ||
8104 | } | ||
8105 | 8513 | ||
8106 | static void alc888_3st_hp_unsol_event(struct hda_codec *codec, | 8514 | static void alc888_3st_hp_init_hook(struct hda_codec *codec) |
8107 | unsigned int res) | ||
8108 | { | 8515 | { |
8109 | switch (res >> 26) { | 8516 | struct alc_spec *spec = codec->spec; |
8110 | case ALC880_HP_EVENT: | 8517 | |
8111 | alc888_3st_hp_front_automute(codec); | 8518 | spec->autocfg.hp_pins[0] = 0x1b; |
8112 | break; | 8519 | spec->autocfg.speaker_pins[0] = 0x14; |
8113 | } | 8520 | spec->autocfg.speaker_pins[1] = 0x16; |
8521 | spec->autocfg.speaker_pins[2] = 0x18; | ||
8522 | alc_automute_amp(codec); | ||
8114 | } | 8523 | } |
8115 | 8524 | ||
8116 | static struct hda_verb alc888_3st_hp_verbs[] = { | 8525 | static struct hda_verb alc888_3st_hp_verbs[] = { |
@@ -8207,56 +8616,18 @@ static struct hda_verb alc883_medion_md2_verbs[] = { | |||
8207 | }; | 8616 | }; |
8208 | 8617 | ||
8209 | /* toggle speaker-output according to the hp-jack state */ | 8618 | /* toggle speaker-output according to the hp-jack state */ |
8210 | static void alc883_medion_md2_automute(struct hda_codec *codec) | 8619 | static void alc883_medion_md2_init_hook(struct hda_codec *codec) |
8211 | { | 8620 | { |
8212 | unsigned int present; | 8621 | struct alc_spec *spec = codec->spec; |
8213 | |||
8214 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
8215 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
8216 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
8217 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8218 | } | ||
8219 | |||
8220 | static void alc883_medion_md2_unsol_event(struct hda_codec *codec, | ||
8221 | unsigned int res) | ||
8222 | { | ||
8223 | if ((res >> 26) == ALC880_HP_EVENT) | ||
8224 | alc883_medion_md2_automute(codec); | ||
8225 | } | ||
8226 | |||
8227 | /* toggle speaker-output according to the hp-jack state */ | ||
8228 | static void alc883_tagra_automute(struct hda_codec *codec) | ||
8229 | { | ||
8230 | unsigned int present; | ||
8231 | unsigned char bits; | ||
8232 | |||
8233 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
8234 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
8235 | bits = present ? HDA_AMP_MUTE : 0; | ||
8236 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
8237 | HDA_AMP_MUTE, bits); | ||
8238 | snd_hda_codec_write_cache(codec, 1, 0, AC_VERB_SET_GPIO_DATA, | ||
8239 | present ? 1 : 3); | ||
8240 | } | ||
8241 | 8622 | ||
8242 | static void alc883_tagra_unsol_event(struct hda_codec *codec, unsigned int res) | 8623 | spec->autocfg.hp_pins[0] = 0x14; |
8243 | { | 8624 | spec->autocfg.speaker_pins[0] = 0x15; |
8244 | if ((res >> 26) == ALC880_HP_EVENT) | 8625 | alc_automute_amp(codec); |
8245 | alc883_tagra_automute(codec); | ||
8246 | } | 8626 | } |
8247 | 8627 | ||
8248 | /* toggle speaker-output according to the hp-jack state */ | 8628 | /* toggle speaker-output according to the hp-jack state */ |
8249 | static void alc883_clevo_m720_hp_automute(struct hda_codec *codec) | 8629 | #define alc883_tagra_init_hook alc882_targa_init_hook |
8250 | { | 8630 | #define alc883_tagra_unsol_event alc882_targa_unsol_event |
8251 | unsigned int present; | ||
8252 | unsigned char bits; | ||
8253 | |||
8254 | present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) | ||
8255 | & AC_PINSENSE_PRESENCE; | ||
8256 | bits = present ? HDA_AMP_MUTE : 0; | ||
8257 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8258 | HDA_AMP_MUTE, bits); | ||
8259 | } | ||
8260 | 8631 | ||
8261 | static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) | 8632 | static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) |
8262 | { | 8633 | { |
@@ -8268,9 +8639,13 @@ static void alc883_clevo_m720_mic_automute(struct hda_codec *codec) | |||
8268 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | 8639 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); |
8269 | } | 8640 | } |
8270 | 8641 | ||
8271 | static void alc883_clevo_m720_automute(struct hda_codec *codec) | 8642 | static void alc883_clevo_m720_init_hook(struct hda_codec *codec) |
8272 | { | 8643 | { |
8273 | alc883_clevo_m720_hp_automute(codec); | 8644 | struct alc_spec *spec = codec->spec; |
8645 | |||
8646 | spec->autocfg.hp_pins[0] = 0x15; | ||
8647 | spec->autocfg.speaker_pins[0] = 0x14; | ||
8648 | alc_automute_amp(codec); | ||
8274 | alc883_clevo_m720_mic_automute(codec); | 8649 | alc883_clevo_m720_mic_automute(codec); |
8275 | } | 8650 | } |
8276 | 8651 | ||
@@ -8278,52 +8653,32 @@ static void alc883_clevo_m720_unsol_event(struct hda_codec *codec, | |||
8278 | unsigned int res) | 8653 | unsigned int res) |
8279 | { | 8654 | { |
8280 | switch (res >> 26) { | 8655 | switch (res >> 26) { |
8281 | case ALC880_HP_EVENT: | ||
8282 | alc883_clevo_m720_hp_automute(codec); | ||
8283 | break; | ||
8284 | case ALC880_MIC_EVENT: | 8656 | case ALC880_MIC_EVENT: |
8285 | alc883_clevo_m720_mic_automute(codec); | 8657 | alc883_clevo_m720_mic_automute(codec); |
8286 | break; | 8658 | break; |
8659 | default: | ||
8660 | alc_automute_amp_unsol_event(codec, res); | ||
8661 | break; | ||
8287 | } | 8662 | } |
8288 | } | 8663 | } |
8289 | 8664 | ||
8290 | /* toggle speaker-output according to the hp-jack state */ | 8665 | /* toggle speaker-output according to the hp-jack state */ |
8291 | static void alc883_2ch_fujitsu_pi2515_automute(struct hda_codec *codec) | 8666 | static void alc883_2ch_fujitsu_pi2515_init_hook(struct hda_codec *codec) |
8292 | { | 8667 | { |
8293 | unsigned int present; | 8668 | struct alc_spec *spec = codec->spec; |
8294 | unsigned char bits; | ||
8295 | |||
8296 | present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) | ||
8297 | & AC_PINSENSE_PRESENCE; | ||
8298 | bits = present ? HDA_AMP_MUTE : 0; | ||
8299 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
8300 | HDA_AMP_MUTE, bits); | ||
8301 | } | ||
8302 | 8669 | ||
8303 | static void alc883_2ch_fujitsu_pi2515_unsol_event(struct hda_codec *codec, | 8670 | spec->autocfg.hp_pins[0] = 0x14; |
8304 | unsigned int res) | 8671 | spec->autocfg.speaker_pins[0] = 0x15; |
8305 | { | 8672 | alc_automute_amp(codec); |
8306 | if ((res >> 26) == ALC880_HP_EVENT) | ||
8307 | alc883_2ch_fujitsu_pi2515_automute(codec); | ||
8308 | } | 8673 | } |
8309 | 8674 | ||
8310 | static void alc883_haier_w66_automute(struct hda_codec *codec) | 8675 | static void alc883_haier_w66_init_hook(struct hda_codec *codec) |
8311 | { | 8676 | { |
8312 | unsigned int present; | 8677 | struct alc_spec *spec = codec->spec; |
8313 | unsigned char bits; | ||
8314 | 8678 | ||
8315 | present = snd_hda_codec_read(codec, 0x1b, 0, | 8679 | spec->autocfg.hp_pins[0] = 0x1b; |
8316 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 8680 | spec->autocfg.speaker_pins[0] = 0x14; |
8317 | bits = present ? 0x80 : 0; | 8681 | alc_automute_amp(codec); |
8318 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8319 | 0x80, bits); | ||
8320 | } | ||
8321 | |||
8322 | static void alc883_haier_w66_unsol_event(struct hda_codec *codec, | ||
8323 | unsigned int res) | ||
8324 | { | ||
8325 | if ((res >> 26) == ALC880_HP_EVENT) | ||
8326 | alc883_haier_w66_automute(codec); | ||
8327 | } | 8682 | } |
8328 | 8683 | ||
8329 | static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) | 8684 | static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) |
@@ -8331,8 +8686,8 @@ static void alc883_lenovo_101e_ispeaker_automute(struct hda_codec *codec) | |||
8331 | unsigned int present; | 8686 | unsigned int present; |
8332 | unsigned char bits; | 8687 | unsigned char bits; |
8333 | 8688 | ||
8334 | present = snd_hda_codec_read(codec, 0x14, 0, | 8689 | present = snd_hda_codec_read(codec, 0x14, 0, AC_VERB_GET_PIN_SENSE, 0) |
8335 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | 8690 | & AC_PINSENSE_PRESENCE; |
8336 | bits = present ? HDA_AMP_MUTE : 0; | 8691 | bits = present ? HDA_AMP_MUTE : 0; |
8337 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | 8692 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, |
8338 | HDA_AMP_MUTE, bits); | 8693 | HDA_AMP_MUTE, bits); |
@@ -8362,23 +8717,14 @@ static void alc883_lenovo_101e_unsol_event(struct hda_codec *codec, | |||
8362 | } | 8717 | } |
8363 | 8718 | ||
8364 | /* toggle speaker-output according to the hp-jack state */ | 8719 | /* toggle speaker-output according to the hp-jack state */ |
8365 | static void alc883_acer_aspire_automute(struct hda_codec *codec) | 8720 | static void alc883_acer_aspire_init_hook(struct hda_codec *codec) |
8366 | { | 8721 | { |
8367 | unsigned int present; | 8722 | struct alc_spec *spec = codec->spec; |
8368 | |||
8369 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
8370 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
8371 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
8372 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8373 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
8374 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8375 | } | ||
8376 | 8723 | ||
8377 | static void alc883_acer_aspire_unsol_event(struct hda_codec *codec, | 8724 | spec->autocfg.hp_pins[0] = 0x14; |
8378 | unsigned int res) | 8725 | spec->autocfg.speaker_pins[0] = 0x15; |
8379 | { | 8726 | spec->autocfg.speaker_pins[1] = 0x16; |
8380 | if ((res >> 26) == ALC880_HP_EVENT) | 8727 | alc_automute_amp(codec); |
8381 | alc883_acer_aspire_automute(codec); | ||
8382 | } | 8728 | } |
8383 | 8729 | ||
8384 | static struct hda_verb alc883_acer_eapd_verbs[] = { | 8730 | static struct hda_verb alc883_acer_eapd_verbs[] = { |
@@ -8399,75 +8745,39 @@ static struct hda_verb alc883_acer_eapd_verbs[] = { | |||
8399 | { } | 8745 | { } |
8400 | }; | 8746 | }; |
8401 | 8747 | ||
8402 | static void alc888_6st_dell_front_automute(struct hda_codec *codec) | 8748 | static void alc888_6st_dell_init_hook(struct hda_codec *codec) |
8403 | { | 8749 | { |
8404 | unsigned int present; | 8750 | struct alc_spec *spec = codec->spec; |
8405 | |||
8406 | present = snd_hda_codec_read(codec, 0x1b, 0, | ||
8407 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
8408 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8409 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8410 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
8411 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8412 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
8413 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8414 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
8415 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8416 | } | ||
8417 | 8751 | ||
8418 | static void alc888_6st_dell_unsol_event(struct hda_codec *codec, | 8752 | spec->autocfg.hp_pins[0] = 0x1b; |
8419 | unsigned int res) | 8753 | spec->autocfg.speaker_pins[0] = 0x14; |
8420 | { | 8754 | spec->autocfg.speaker_pins[1] = 0x15; |
8421 | switch (res >> 26) { | 8755 | spec->autocfg.speaker_pins[2] = 0x16; |
8422 | case ALC880_HP_EVENT: | 8756 | spec->autocfg.speaker_pins[3] = 0x17; |
8423 | /* printk(KERN_DEBUG "hp_event\n"); */ | 8757 | alc_automute_amp(codec); |
8424 | alc888_6st_dell_front_automute(codec); | ||
8425 | break; | ||
8426 | } | ||
8427 | } | 8758 | } |
8428 | 8759 | ||
8429 | static void alc888_lenovo_sky_front_automute(struct hda_codec *codec) | 8760 | static void alc888_lenovo_sky_init_hook(struct hda_codec *codec) |
8430 | { | 8761 | { |
8431 | unsigned int mute; | 8762 | struct alc_spec *spec = codec->spec; |
8432 | unsigned int present; | ||
8433 | 8763 | ||
8434 | snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); | 8764 | spec->autocfg.hp_pins[0] = 0x1b; |
8435 | present = snd_hda_codec_read(codec, 0x1b, 0, | 8765 | spec->autocfg.speaker_pins[0] = 0x14; |
8436 | AC_VERB_GET_PIN_SENSE, 0); | 8766 | spec->autocfg.speaker_pins[1] = 0x15; |
8437 | present = (present & 0x80000000) != 0; | 8767 | spec->autocfg.speaker_pins[2] = 0x16; |
8438 | if (present) { | 8768 | spec->autocfg.speaker_pins[3] = 0x17; |
8439 | /* mute internal speaker */ | 8769 | spec->autocfg.speaker_pins[4] = 0x1a; |
8440 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | 8770 | alc_automute_amp(codec); |
8441 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
8442 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
8443 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
8444 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
8445 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
8446 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
8447 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
8448 | snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, | ||
8449 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
8450 | } else { | ||
8451 | /* unmute internal speaker if necessary */ | ||
8452 | mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); | ||
8453 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8454 | HDA_AMP_MUTE, mute); | ||
8455 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
8456 | HDA_AMP_MUTE, mute); | ||
8457 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
8458 | HDA_AMP_MUTE, mute); | ||
8459 | snd_hda_codec_amp_stereo(codec, 0x17, HDA_OUTPUT, 0, | ||
8460 | HDA_AMP_MUTE, mute); | ||
8461 | snd_hda_codec_amp_stereo(codec, 0x1a, HDA_OUTPUT, 0, | ||
8462 | HDA_AMP_MUTE, mute); | ||
8463 | } | ||
8464 | } | 8771 | } |
8465 | 8772 | ||
8466 | static void alc883_lenovo_sky_unsol_event(struct hda_codec *codec, | 8773 | static void alc883_vaiott_init_hook(struct hda_codec *codec) |
8467 | unsigned int res) | ||
8468 | { | 8774 | { |
8469 | if ((res >> 26) == ALC880_HP_EVENT) | 8775 | struct alc_spec *spec = codec->spec; |
8470 | alc888_lenovo_sky_front_automute(codec); | 8776 | |
8777 | spec->autocfg.hp_pins[0] = 0x15; | ||
8778 | spec->autocfg.speaker_pins[0] = 0x14; | ||
8779 | spec->autocfg.speaker_pins[1] = 0x17; | ||
8780 | alc_automute_amp(codec); | ||
8471 | } | 8781 | } |
8472 | 8782 | ||
8473 | /* | 8783 | /* |
@@ -8555,39 +8865,33 @@ static void alc883_nb_mic_automute(struct hda_codec *codec) | |||
8555 | 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); | 8865 | 0x7000 | (0x01 << 8) | (present ? 0x80 : 0)); |
8556 | } | 8866 | } |
8557 | 8867 | ||
8558 | static void alc883_M90V_speaker_automute(struct hda_codec *codec) | 8868 | static void alc883_M90V_init_hook(struct hda_codec *codec) |
8559 | { | 8869 | { |
8560 | unsigned int present; | 8870 | struct alc_spec *spec = codec->spec; |
8561 | unsigned char bits; | ||
8562 | 8871 | ||
8563 | present = snd_hda_codec_read(codec, 0x1b, 0, | 8872 | spec->autocfg.hp_pins[0] = 0x1b; |
8564 | AC_VERB_GET_PIN_SENSE, 0) | 8873 | spec->autocfg.speaker_pins[0] = 0x14; |
8565 | & AC_PINSENSE_PRESENCE; | 8874 | spec->autocfg.speaker_pins[1] = 0x15; |
8566 | bits = present ? 0 : PIN_OUT; | 8875 | spec->autocfg.speaker_pins[2] = 0x16; |
8567 | snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | 8876 | alc_automute_pin(codec); |
8568 | bits); | ||
8569 | snd_hda_codec_write(codec, 0x15, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8570 | bits); | ||
8571 | snd_hda_codec_write(codec, 0x16, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8572 | bits); | ||
8573 | } | 8877 | } |
8574 | 8878 | ||
8575 | static void alc883_mode2_unsol_event(struct hda_codec *codec, | 8879 | static void alc883_mode2_unsol_event(struct hda_codec *codec, |
8576 | unsigned int res) | 8880 | unsigned int res) |
8577 | { | 8881 | { |
8578 | switch (res >> 26) { | 8882 | switch (res >> 26) { |
8579 | case ALC880_HP_EVENT: | ||
8580 | alc883_M90V_speaker_automute(codec); | ||
8581 | break; | ||
8582 | case ALC880_MIC_EVENT: | 8883 | case ALC880_MIC_EVENT: |
8583 | alc883_nb_mic_automute(codec); | 8884 | alc883_nb_mic_automute(codec); |
8584 | break; | 8885 | break; |
8886 | default: | ||
8887 | alc_sku_unsol_event(codec, res); | ||
8888 | break; | ||
8585 | } | 8889 | } |
8586 | } | 8890 | } |
8587 | 8891 | ||
8588 | static void alc883_mode2_inithook(struct hda_codec *codec) | 8892 | static void alc883_mode2_inithook(struct hda_codec *codec) |
8589 | { | 8893 | { |
8590 | alc883_M90V_speaker_automute(codec); | 8894 | alc883_M90V_init_hook(codec); |
8591 | alc883_nb_mic_automute(codec); | 8895 | alc883_nb_mic_automute(codec); |
8592 | } | 8896 | } |
8593 | 8897 | ||
@@ -8604,32 +8908,49 @@ static struct hda_verb alc888_asus_eee1601_verbs[] = { | |||
8604 | { } /* end */ | 8908 | { } /* end */ |
8605 | }; | 8909 | }; |
8606 | 8910 | ||
8607 | static void alc883_eee1601_speaker_automute(struct hda_codec *codec) | 8911 | static void alc883_eee1601_inithook(struct hda_codec *codec) |
8608 | { | 8912 | { |
8609 | unsigned int present; | 8913 | struct alc_spec *spec = codec->spec; |
8610 | unsigned char bits; | ||
8611 | 8914 | ||
8612 | present = snd_hda_codec_read(codec, 0x14, 0, | 8915 | spec->autocfg.hp_pins[0] = 0x14; |
8613 | AC_VERB_GET_PIN_SENSE, 0) | 8916 | spec->autocfg.speaker_pins[0] = 0x1b; |
8614 | & AC_PINSENSE_PRESENCE; | 8917 | alc_automute_pin(codec); |
8615 | bits = present ? 0 : PIN_OUT; | ||
8616 | snd_hda_codec_write(codec, 0x1b, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
8617 | bits); | ||
8618 | } | 8918 | } |
8619 | 8919 | ||
8620 | static void alc883_eee1601_unsol_event(struct hda_codec *codec, | 8920 | static struct hda_verb alc889A_mb31_verbs[] = { |
8621 | unsigned int res) | 8921 | /* Init rear pin (used as headphone output) */ |
8922 | {0x15, AC_VERB_SET_PIN_WIDGET_CONTROL, 0xc4}, /* Apple Headphones */ | ||
8923 | {0x15, AC_VERB_SET_CONNECT_SEL, 0x00}, /* Connect to front */ | ||
8924 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | ||
8925 | /* Init line pin (used as output in 4ch and 6ch mode) */ | ||
8926 | {0x1a, AC_VERB_SET_CONNECT_SEL, 0x02}, /* Connect to CLFE */ | ||
8927 | /* Init line 2 pin (used as headphone out by default) */ | ||
8928 | {0x1b, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN}, /* Use as input */ | ||
8929 | {0x1b, AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE}, /* Mute output */ | ||
8930 | { } /* end */ | ||
8931 | }; | ||
8932 | |||
8933 | /* Mute speakers according to the headphone jack state */ | ||
8934 | static void alc889A_mb31_automute(struct hda_codec *codec) | ||
8622 | { | 8935 | { |
8623 | switch (res >> 26) { | 8936 | unsigned int present; |
8624 | case ALC880_HP_EVENT: | 8937 | |
8625 | alc883_eee1601_speaker_automute(codec); | 8938 | /* Mute only in 2ch or 4ch mode */ |
8626 | break; | 8939 | if (snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_CONNECT_SEL, 0) |
8940 | == 0x00) { | ||
8941 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
8942 | AC_VERB_GET_PIN_SENSE, 0) & AC_PINSENSE_PRESENCE; | ||
8943 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
8944 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8945 | snd_hda_codec_amp_stereo(codec, 0x16, HDA_OUTPUT, 0, | ||
8946 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
8627 | } | 8947 | } |
8628 | } | 8948 | } |
8629 | 8949 | ||
8630 | static void alc883_eee1601_inithook(struct hda_codec *codec) | 8950 | static void alc889A_mb31_unsol_event(struct hda_codec *codec, unsigned int res) |
8631 | { | 8951 | { |
8632 | alc883_eee1601_speaker_automute(codec); | 8952 | if ((res >> 26) == ALC880_HP_EVENT) |
8953 | alc889A_mb31_automute(codec); | ||
8633 | } | 8954 | } |
8634 | 8955 | ||
8635 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 8956 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
@@ -8653,9 +8974,11 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { | |||
8653 | [ALC883_6ST_DIG] = "6stack-dig", | 8974 | [ALC883_6ST_DIG] = "6stack-dig", |
8654 | [ALC883_TARGA_DIG] = "targa-dig", | 8975 | [ALC883_TARGA_DIG] = "targa-dig", |
8655 | [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", | 8976 | [ALC883_TARGA_2ch_DIG] = "targa-2ch-dig", |
8977 | [ALC883_TARGA_8ch_DIG] = "targa-8ch-dig", | ||
8656 | [ALC883_ACER] = "acer", | 8978 | [ALC883_ACER] = "acer", |
8657 | [ALC883_ACER_ASPIRE] = "acer-aspire", | 8979 | [ALC883_ACER_ASPIRE] = "acer-aspire", |
8658 | [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", | 8980 | [ALC888_ACER_ASPIRE_4930G] = "acer-aspire-4930g", |
8981 | [ALC888_ACER_ASPIRE_8930G] = "acer-aspire-8930g", | ||
8659 | [ALC883_MEDION] = "medion", | 8982 | [ALC883_MEDION] = "medion", |
8660 | [ALC883_MEDION_MD2] = "medion-md2", | 8983 | [ALC883_MEDION_MD2] = "medion-md2", |
8661 | [ALC883_LAPTOP_EAPD] = "laptop-eapd", | 8984 | [ALC883_LAPTOP_EAPD] = "laptop-eapd", |
@@ -8672,6 +8995,8 @@ static const char *alc883_models[ALC883_MODEL_LAST] = { | |||
8672 | [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", | 8995 | [ALC888_FUJITSU_XA3530] = "fujitsu-xa3530", |
8673 | [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", | 8996 | [ALC883_3ST_6ch_INTEL] = "3stack-6ch-intel", |
8674 | [ALC1200_ASUS_P5Q] = "asus-p5q", | 8997 | [ALC1200_ASUS_P5Q] = "asus-p5q", |
8998 | [ALC889A_MB31] = "mb31", | ||
8999 | [ALC883_SONY_VAIO_TT] = "sony-vaio-tt", | ||
8675 | [ALC883_AUTO] = "auto", | 9000 | [ALC883_AUTO] = "auto", |
8676 | }; | 9001 | }; |
8677 | 9002 | ||
@@ -8687,14 +9012,18 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { | |||
8687 | ALC888_ACER_ASPIRE_4930G), | 9012 | ALC888_ACER_ASPIRE_4930G), |
8688 | SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", | 9013 | SND_PCI_QUIRK(0x1025, 0x013f, "Acer Aspire 5930G", |
8689 | ALC888_ACER_ASPIRE_4930G), | 9014 | ALC888_ACER_ASPIRE_4930G), |
9015 | SND_PCI_QUIRK(0x1025, 0x0145, "Acer Aspire 8930G", | ||
9016 | ALC888_ACER_ASPIRE_8930G), | ||
8690 | SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), | 9017 | SND_PCI_QUIRK(0x1025, 0x0157, "Acer X3200", ALC883_AUTO), |
8691 | SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), | 9018 | SND_PCI_QUIRK(0x1025, 0x0158, "Acer AX1700-U3700A", ALC883_AUTO), |
8692 | SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", | 9019 | SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G", |
8693 | ALC888_ACER_ASPIRE_4930G), | 9020 | ALC888_ACER_ASPIRE_4930G), |
8694 | SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", | 9021 | SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G", |
8695 | ALC888_ACER_ASPIRE_4930G), | 9022 | ALC888_ACER_ASPIRE_4930G), |
8696 | /* default Acer */ | 9023 | /* default Acer -- disabled as it causes more problems. |
8697 | SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), | 9024 | * model=auto should work fine now |
9025 | */ | ||
9026 | /* SND_PCI_QUIRK_VENDOR(0x1025, "Acer laptop", ALC883_ACER), */ | ||
8698 | SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), | 9027 | SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL), |
8699 | SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), | 9028 | SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG), |
8700 | SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), | 9029 | SND_PCI_QUIRK(0x103c, 0x2a4f, "HP Samba", ALC888_3ST_HP), |
@@ -8730,6 +9059,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { | |||
8730 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), | 9059 | SND_PCI_QUIRK(0x1462, 0x4314, "MSI", ALC883_TARGA_DIG), |
8731 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), | 9060 | SND_PCI_QUIRK(0x1462, 0x4319, "MSI", ALC883_TARGA_DIG), |
8732 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), | 9061 | SND_PCI_QUIRK(0x1462, 0x4324, "MSI", ALC883_TARGA_DIG), |
9062 | SND_PCI_QUIRK(0x1462, 0x6510, "MSI GX620", ALC883_TARGA_8ch_DIG), | ||
8733 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), | 9063 | SND_PCI_QUIRK(0x1462, 0x6668, "MSI", ALC883_6ST_DIG), |
8734 | SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), | 9064 | SND_PCI_QUIRK(0x1462, 0x7187, "MSI", ALC883_6ST_DIG), |
8735 | SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), | 9065 | SND_PCI_QUIRK(0x1462, 0x7250, "MSI", ALC883_6ST_DIG), |
@@ -8762,6 +9092,7 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = { | |||
8762 | SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), | 9092 | SND_PCI_QUIRK(0x8086, 0x2503, "82801H", ALC883_MITAC), |
8763 | SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL), | 9093 | SND_PCI_QUIRK(0x8086, 0x0022, "DX58SO", ALC883_3ST_6ch_INTEL), |
8764 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), | 9094 | SND_PCI_QUIRK(0x8086, 0xd601, "D102GGC", ALC883_3ST_6ch), |
9095 | SND_PCI_QUIRK(0x104d, 0x9047, "Sony Vaio TT", ALC883_SONY_VAIO_TT), | ||
8765 | {} | 9096 | {} |
8766 | }; | 9097 | }; |
8767 | 9098 | ||
@@ -8842,7 +9173,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
8842 | .need_dac_fix = 1, | 9173 | .need_dac_fix = 1, |
8843 | .input_mux = &alc883_capture_source, | 9174 | .input_mux = &alc883_capture_source, |
8844 | .unsol_event = alc883_tagra_unsol_event, | 9175 | .unsol_event = alc883_tagra_unsol_event, |
8845 | .init_hook = alc883_tagra_automute, | 9176 | .init_hook = alc883_tagra_init_hook, |
8846 | }, | 9177 | }, |
8847 | [ALC883_TARGA_2ch_DIG] = { | 9178 | [ALC883_TARGA_2ch_DIG] = { |
8848 | .mixers = { alc883_tagra_2ch_mixer}, | 9179 | .mixers = { alc883_tagra_2ch_mixer}, |
@@ -8856,7 +9187,25 @@ static struct alc_config_preset alc883_presets[] = { | |||
8856 | .channel_mode = alc883_3ST_2ch_modes, | 9187 | .channel_mode = alc883_3ST_2ch_modes, |
8857 | .input_mux = &alc883_capture_source, | 9188 | .input_mux = &alc883_capture_source, |
8858 | .unsol_event = alc883_tagra_unsol_event, | 9189 | .unsol_event = alc883_tagra_unsol_event, |
8859 | .init_hook = alc883_tagra_automute, | 9190 | .init_hook = alc883_tagra_init_hook, |
9191 | }, | ||
9192 | [ALC883_TARGA_8ch_DIG] = { | ||
9193 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, | ||
9194 | .init_verbs = { alc883_init_verbs, alc880_gpio3_init_verbs, | ||
9195 | alc883_tagra_verbs }, | ||
9196 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
9197 | .dac_nids = alc883_dac_nids, | ||
9198 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids_rev), | ||
9199 | .adc_nids = alc883_adc_nids_rev, | ||
9200 | .capsrc_nids = alc883_capsrc_nids_rev, | ||
9201 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
9202 | .dig_in_nid = ALC883_DIGIN_NID, | ||
9203 | .num_channel_mode = ARRAY_SIZE(alc883_4ST_8ch_modes), | ||
9204 | .channel_mode = alc883_4ST_8ch_modes, | ||
9205 | .need_dac_fix = 1, | ||
9206 | .input_mux = &alc883_capture_source, | ||
9207 | .unsol_event = alc883_tagra_unsol_event, | ||
9208 | .init_hook = alc883_tagra_init_hook, | ||
8860 | }, | 9209 | }, |
8861 | [ALC883_ACER] = { | 9210 | [ALC883_ACER] = { |
8862 | .mixers = { alc883_base_mixer }, | 9211 | .mixers = { alc883_base_mixer }, |
@@ -8881,8 +9230,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
8881 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | 9230 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), |
8882 | .channel_mode = alc883_3ST_2ch_modes, | 9231 | .channel_mode = alc883_3ST_2ch_modes, |
8883 | .input_mux = &alc883_capture_source, | 9232 | .input_mux = &alc883_capture_source, |
8884 | .unsol_event = alc883_acer_aspire_unsol_event, | 9233 | .unsol_event = alc_automute_amp_unsol_event, |
8885 | .init_hook = alc883_acer_aspire_automute, | 9234 | .init_hook = alc883_acer_aspire_init_hook, |
8886 | }, | 9235 | }, |
8887 | [ALC888_ACER_ASPIRE_4930G] = { | 9236 | [ALC888_ACER_ASPIRE_4930G] = { |
8888 | .mixers = { alc888_base_mixer, | 9237 | .mixers = { alc888_base_mixer, |
@@ -8901,8 +9250,29 @@ static struct alc_config_preset alc883_presets[] = { | |||
8901 | .num_mux_defs = | 9250 | .num_mux_defs = |
8902 | ARRAY_SIZE(alc888_2_capture_sources), | 9251 | ARRAY_SIZE(alc888_2_capture_sources), |
8903 | .input_mux = alc888_2_capture_sources, | 9252 | .input_mux = alc888_2_capture_sources, |
8904 | .unsol_event = alc888_acer_aspire_4930g_unsol_event, | 9253 | .unsol_event = alc_automute_amp_unsol_event, |
8905 | .init_hook = alc888_acer_aspire_4930g_automute, | 9254 | .init_hook = alc888_acer_aspire_4930g_init_hook, |
9255 | }, | ||
9256 | [ALC888_ACER_ASPIRE_8930G] = { | ||
9257 | .mixers = { alc888_base_mixer, | ||
9258 | alc883_chmode_mixer }, | ||
9259 | .init_verbs = { alc883_init_verbs, alc880_gpio1_init_verbs, | ||
9260 | alc889_acer_aspire_8930g_verbs }, | ||
9261 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
9262 | .dac_nids = alc883_dac_nids, | ||
9263 | .num_adc_nids = ARRAY_SIZE(alc889_adc_nids), | ||
9264 | .adc_nids = alc889_adc_nids, | ||
9265 | .capsrc_nids = alc889_capsrc_nids, | ||
9266 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
9267 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_6ch_modes), | ||
9268 | .channel_mode = alc883_3ST_6ch_modes, | ||
9269 | .need_dac_fix = 1, | ||
9270 | .const_channel_count = 6, | ||
9271 | .num_mux_defs = | ||
9272 | ARRAY_SIZE(alc889_capture_sources), | ||
9273 | .input_mux = alc889_capture_sources, | ||
9274 | .unsol_event = alc_automute_amp_unsol_event, | ||
9275 | .init_hook = alc889_acer_aspire_8930g_init_hook, | ||
8906 | }, | 9276 | }, |
8907 | [ALC883_MEDION] = { | 9277 | [ALC883_MEDION] = { |
8908 | .mixers = { alc883_fivestack_mixer, | 9278 | .mixers = { alc883_fivestack_mixer, |
@@ -8926,8 +9296,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
8926 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | 9296 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), |
8927 | .channel_mode = alc883_3ST_2ch_modes, | 9297 | .channel_mode = alc883_3ST_2ch_modes, |
8928 | .input_mux = &alc883_capture_source, | 9298 | .input_mux = &alc883_capture_source, |
8929 | .unsol_event = alc883_medion_md2_unsol_event, | 9299 | .unsol_event = alc_automute_amp_unsol_event, |
8930 | .init_hook = alc883_medion_md2_automute, | 9300 | .init_hook = alc883_medion_md2_init_hook, |
8931 | }, | 9301 | }, |
8932 | [ALC883_LAPTOP_EAPD] = { | 9302 | [ALC883_LAPTOP_EAPD] = { |
8933 | .mixers = { alc883_base_mixer }, | 9303 | .mixers = { alc883_base_mixer }, |
@@ -8948,7 +9318,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
8948 | .channel_mode = alc883_3ST_2ch_modes, | 9318 | .channel_mode = alc883_3ST_2ch_modes, |
8949 | .input_mux = &alc883_capture_source, | 9319 | .input_mux = &alc883_capture_source, |
8950 | .unsol_event = alc883_clevo_m720_unsol_event, | 9320 | .unsol_event = alc883_clevo_m720_unsol_event, |
8951 | .init_hook = alc883_clevo_m720_automute, | 9321 | .init_hook = alc883_clevo_m720_init_hook, |
8952 | }, | 9322 | }, |
8953 | [ALC883_LENOVO_101E_2ch] = { | 9323 | [ALC883_LENOVO_101E_2ch] = { |
8954 | .mixers = { alc883_lenovo_101e_2ch_mixer}, | 9324 | .mixers = { alc883_lenovo_101e_2ch_mixer}, |
@@ -8972,8 +9342,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
8972 | .channel_mode = alc883_3ST_2ch_modes, | 9342 | .channel_mode = alc883_3ST_2ch_modes, |
8973 | .need_dac_fix = 1, | 9343 | .need_dac_fix = 1, |
8974 | .input_mux = &alc883_lenovo_nb0763_capture_source, | 9344 | .input_mux = &alc883_lenovo_nb0763_capture_source, |
8975 | .unsol_event = alc883_medion_md2_unsol_event, | 9345 | .unsol_event = alc_automute_amp_unsol_event, |
8976 | .init_hook = alc883_medion_md2_automute, | 9346 | .init_hook = alc883_medion_md2_init_hook, |
8977 | }, | 9347 | }, |
8978 | [ALC888_LENOVO_MS7195_DIG] = { | 9348 | [ALC888_LENOVO_MS7195_DIG] = { |
8979 | .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, | 9349 | .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, |
@@ -8997,8 +9367,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
8997 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | 9367 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), |
8998 | .channel_mode = alc883_3ST_2ch_modes, | 9368 | .channel_mode = alc883_3ST_2ch_modes, |
8999 | .input_mux = &alc883_capture_source, | 9369 | .input_mux = &alc883_capture_source, |
9000 | .unsol_event = alc883_haier_w66_unsol_event, | 9370 | .unsol_event = alc_automute_amp_unsol_event, |
9001 | .init_hook = alc883_haier_w66_automute, | 9371 | .init_hook = alc883_haier_w66_init_hook, |
9002 | }, | 9372 | }, |
9003 | [ALC888_3ST_HP] = { | 9373 | [ALC888_3ST_HP] = { |
9004 | .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, | 9374 | .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, |
@@ -9009,8 +9379,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
9009 | .channel_mode = alc888_3st_hp_modes, | 9379 | .channel_mode = alc888_3st_hp_modes, |
9010 | .need_dac_fix = 1, | 9380 | .need_dac_fix = 1, |
9011 | .input_mux = &alc883_capture_source, | 9381 | .input_mux = &alc883_capture_source, |
9012 | .unsol_event = alc888_3st_hp_unsol_event, | 9382 | .unsol_event = alc_automute_amp_unsol_event, |
9013 | .init_hook = alc888_3st_hp_front_automute, | 9383 | .init_hook = alc888_3st_hp_init_hook, |
9014 | }, | 9384 | }, |
9015 | [ALC888_6ST_DELL] = { | 9385 | [ALC888_6ST_DELL] = { |
9016 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, | 9386 | .mixers = { alc883_base_mixer, alc883_chmode_mixer }, |
@@ -9022,8 +9392,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
9022 | .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), | 9392 | .num_channel_mode = ARRAY_SIZE(alc883_sixstack_modes), |
9023 | .channel_mode = alc883_sixstack_modes, | 9393 | .channel_mode = alc883_sixstack_modes, |
9024 | .input_mux = &alc883_capture_source, | 9394 | .input_mux = &alc883_capture_source, |
9025 | .unsol_event = alc888_6st_dell_unsol_event, | 9395 | .unsol_event = alc_automute_amp_unsol_event, |
9026 | .init_hook = alc888_6st_dell_front_automute, | 9396 | .init_hook = alc888_6st_dell_init_hook, |
9027 | }, | 9397 | }, |
9028 | [ALC883_MITAC] = { | 9398 | [ALC883_MITAC] = { |
9029 | .mixers = { alc883_mitac_mixer }, | 9399 | .mixers = { alc883_mitac_mixer }, |
@@ -9033,8 +9403,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
9033 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | 9403 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), |
9034 | .channel_mode = alc883_3ST_2ch_modes, | 9404 | .channel_mode = alc883_3ST_2ch_modes, |
9035 | .input_mux = &alc883_capture_source, | 9405 | .input_mux = &alc883_capture_source, |
9036 | .unsol_event = alc883_mitac_unsol_event, | 9406 | .unsol_event = alc_automute_amp_unsol_event, |
9037 | .init_hook = alc883_mitac_automute, | 9407 | .init_hook = alc883_mitac_init_hook, |
9038 | }, | 9408 | }, |
9039 | [ALC883_FUJITSU_PI2515] = { | 9409 | [ALC883_FUJITSU_PI2515] = { |
9040 | .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, | 9410 | .mixers = { alc883_2ch_fujitsu_pi2515_mixer }, |
@@ -9046,8 +9416,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
9046 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | 9416 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), |
9047 | .channel_mode = alc883_3ST_2ch_modes, | 9417 | .channel_mode = alc883_3ST_2ch_modes, |
9048 | .input_mux = &alc883_fujitsu_pi2515_capture_source, | 9418 | .input_mux = &alc883_fujitsu_pi2515_capture_source, |
9049 | .unsol_event = alc883_2ch_fujitsu_pi2515_unsol_event, | 9419 | .unsol_event = alc_automute_amp_unsol_event, |
9050 | .init_hook = alc883_2ch_fujitsu_pi2515_automute, | 9420 | .init_hook = alc883_2ch_fujitsu_pi2515_init_hook, |
9051 | }, | 9421 | }, |
9052 | [ALC888_FUJITSU_XA3530] = { | 9422 | [ALC888_FUJITSU_XA3530] = { |
9053 | .mixers = { alc888_base_mixer, alc883_chmode_mixer }, | 9423 | .mixers = { alc888_base_mixer, alc883_chmode_mixer }, |
@@ -9064,8 +9434,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
9064 | .num_mux_defs = | 9434 | .num_mux_defs = |
9065 | ARRAY_SIZE(alc888_2_capture_sources), | 9435 | ARRAY_SIZE(alc888_2_capture_sources), |
9066 | .input_mux = alc888_2_capture_sources, | 9436 | .input_mux = alc888_2_capture_sources, |
9067 | .unsol_event = alc888_fujitsu_xa3530_unsol_event, | 9437 | .unsol_event = alc_automute_amp_unsol_event, |
9068 | .init_hook = alc888_fujitsu_xa3530_automute, | 9438 | .init_hook = alc888_fujitsu_xa3530_init_hook, |
9069 | }, | 9439 | }, |
9070 | [ALC888_LENOVO_SKY] = { | 9440 | [ALC888_LENOVO_SKY] = { |
9071 | .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, | 9441 | .mixers = { alc888_lenovo_sky_mixer, alc883_chmode_mixer }, |
@@ -9077,8 +9447,8 @@ static struct alc_config_preset alc883_presets[] = { | |||
9077 | .channel_mode = alc883_sixstack_modes, | 9447 | .channel_mode = alc883_sixstack_modes, |
9078 | .need_dac_fix = 1, | 9448 | .need_dac_fix = 1, |
9079 | .input_mux = &alc883_lenovo_sky_capture_source, | 9449 | .input_mux = &alc883_lenovo_sky_capture_source, |
9080 | .unsol_event = alc883_lenovo_sky_unsol_event, | 9450 | .unsol_event = alc_automute_amp_unsol_event, |
9081 | .init_hook = alc888_lenovo_sky_front_automute, | 9451 | .init_hook = alc888_lenovo_sky_init_hook, |
9082 | }, | 9452 | }, |
9083 | [ALC888_ASUS_M90V] = { | 9453 | [ALC888_ASUS_M90V] = { |
9084 | .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, | 9454 | .mixers = { alc883_3ST_6ch_mixer, alc883_chmode_mixer }, |
@@ -9106,7 +9476,7 @@ static struct alc_config_preset alc883_presets[] = { | |||
9106 | .channel_mode = alc883_3ST_2ch_modes, | 9476 | .channel_mode = alc883_3ST_2ch_modes, |
9107 | .need_dac_fix = 1, | 9477 | .need_dac_fix = 1, |
9108 | .input_mux = &alc883_asus_eee1601_capture_source, | 9478 | .input_mux = &alc883_asus_eee1601_capture_source, |
9109 | .unsol_event = alc883_eee1601_unsol_event, | 9479 | .unsol_event = alc_sku_unsol_event, |
9110 | .init_hook = alc883_eee1601_inithook, | 9480 | .init_hook = alc883_eee1601_inithook, |
9111 | }, | 9481 | }, |
9112 | [ALC1200_ASUS_P5Q] = { | 9482 | [ALC1200_ASUS_P5Q] = { |
@@ -9121,6 +9491,32 @@ static struct alc_config_preset alc883_presets[] = { | |||
9121 | .channel_mode = alc883_sixstack_modes, | 9491 | .channel_mode = alc883_sixstack_modes, |
9122 | .input_mux = &alc883_capture_source, | 9492 | .input_mux = &alc883_capture_source, |
9123 | }, | 9493 | }, |
9494 | [ALC889A_MB31] = { | ||
9495 | .mixers = { alc889A_mb31_mixer, alc883_chmode_mixer}, | ||
9496 | .init_verbs = { alc883_init_verbs, alc889A_mb31_verbs, | ||
9497 | alc880_gpio1_init_verbs }, | ||
9498 | .adc_nids = alc883_adc_nids, | ||
9499 | .num_adc_nids = ARRAY_SIZE(alc883_adc_nids), | ||
9500 | .dac_nids = alc883_dac_nids, | ||
9501 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
9502 | .channel_mode = alc889A_mb31_6ch_modes, | ||
9503 | .num_channel_mode = ARRAY_SIZE(alc889A_mb31_6ch_modes), | ||
9504 | .input_mux = &alc889A_mb31_capture_source, | ||
9505 | .dig_out_nid = ALC883_DIGOUT_NID, | ||
9506 | .unsol_event = alc889A_mb31_unsol_event, | ||
9507 | .init_hook = alc889A_mb31_automute, | ||
9508 | }, | ||
9509 | [ALC883_SONY_VAIO_TT] = { | ||
9510 | .mixers = { alc883_vaiott_mixer }, | ||
9511 | .init_verbs = { alc883_init_verbs, alc883_vaiott_verbs }, | ||
9512 | .num_dacs = ARRAY_SIZE(alc883_dac_nids), | ||
9513 | .dac_nids = alc883_dac_nids, | ||
9514 | .num_channel_mode = ARRAY_SIZE(alc883_3ST_2ch_modes), | ||
9515 | .channel_mode = alc883_3ST_2ch_modes, | ||
9516 | .input_mux = &alc883_capture_source, | ||
9517 | .unsol_event = alc_automute_amp_unsol_event, | ||
9518 | .init_hook = alc883_vaiott_init_hook, | ||
9519 | }, | ||
9124 | }; | 9520 | }; |
9125 | 9521 | ||
9126 | 9522 | ||
@@ -9149,7 +9545,6 @@ static void alc883_auto_init_multi_out(struct hda_codec *codec) | |||
9149 | struct alc_spec *spec = codec->spec; | 9545 | struct alc_spec *spec = codec->spec; |
9150 | int i; | 9546 | int i; |
9151 | 9547 | ||
9152 | alc_subsystem_id(codec, 0x15, 0x1b, 0x14); | ||
9153 | for (i = 0; i <= HDA_SIDE; i++) { | 9548 | for (i = 0; i <= HDA_SIDE; i++) { |
9154 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 9549 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
9155 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 9550 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -9267,10 +9662,18 @@ static int patch_alc883(struct hda_codec *codec) | |||
9267 | board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, | 9662 | board_config = snd_hda_check_board_config(codec, ALC883_MODEL_LAST, |
9268 | alc883_models, | 9663 | alc883_models, |
9269 | alc883_cfg_tbl); | 9664 | alc883_cfg_tbl); |
9270 | if (board_config < 0) { | 9665 | if (board_config < 0 || board_config >= ALC883_MODEL_LAST) { |
9271 | printk(KERN_INFO "hda_codec: Unknown model for ALC883, " | 9666 | /* Pick up systems that don't supply PCI SSID */ |
9272 | "trying auto-probe from BIOS...\n"); | 9667 | switch (codec->subsystem_id) { |
9273 | board_config = ALC883_AUTO; | 9668 | case 0x106b3600: /* Macbook 3.1 */ |
9669 | board_config = ALC889A_MB31; | ||
9670 | break; | ||
9671 | default: | ||
9672 | printk(KERN_INFO | ||
9673 | "hda_codec: Unknown model for %s, trying " | ||
9674 | "auto-probe from BIOS...\n", codec->chip_name); | ||
9675 | board_config = ALC883_AUTO; | ||
9676 | } | ||
9274 | } | 9677 | } |
9275 | 9678 | ||
9276 | if (board_config == ALC883_AUTO) { | 9679 | if (board_config == ALC883_AUTO) { |
@@ -9298,13 +9701,6 @@ static int patch_alc883(struct hda_codec *codec) | |||
9298 | 9701 | ||
9299 | switch (codec->vendor_id) { | 9702 | switch (codec->vendor_id) { |
9300 | case 0x10ec0888: | 9703 | case 0x10ec0888: |
9301 | if (codec->revision_id == 0x100101) { | ||
9302 | spec->stream_name_analog = "ALC1200 Analog"; | ||
9303 | spec->stream_name_digital = "ALC1200 Digital"; | ||
9304 | } else { | ||
9305 | spec->stream_name_analog = "ALC888 Analog"; | ||
9306 | spec->stream_name_digital = "ALC888 Digital"; | ||
9307 | } | ||
9308 | if (!spec->num_adc_nids) { | 9704 | if (!spec->num_adc_nids) { |
9309 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | 9705 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); |
9310 | spec->adc_nids = alc883_adc_nids; | 9706 | spec->adc_nids = alc883_adc_nids; |
@@ -9312,10 +9708,9 @@ static int patch_alc883(struct hda_codec *codec) | |||
9312 | if (!spec->capsrc_nids) | 9708 | if (!spec->capsrc_nids) |
9313 | spec->capsrc_nids = alc883_capsrc_nids; | 9709 | spec->capsrc_nids = alc883_capsrc_nids; |
9314 | spec->capture_style = CAPT_MIX; /* matrix-style capture */ | 9710 | spec->capture_style = CAPT_MIX; /* matrix-style capture */ |
9711 | spec->init_amp = ALC_INIT_DEFAULT; /* always initialize */ | ||
9315 | break; | 9712 | break; |
9316 | case 0x10ec0889: | 9713 | case 0x10ec0889: |
9317 | spec->stream_name_analog = "ALC889 Analog"; | ||
9318 | spec->stream_name_digital = "ALC889 Digital"; | ||
9319 | if (!spec->num_adc_nids) { | 9714 | if (!spec->num_adc_nids) { |
9320 | spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids); | 9715 | spec->num_adc_nids = ARRAY_SIZE(alc889_adc_nids); |
9321 | spec->adc_nids = alc889_adc_nids; | 9716 | spec->adc_nids = alc889_adc_nids; |
@@ -9326,8 +9721,6 @@ static int patch_alc883(struct hda_codec *codec) | |||
9326 | capture */ | 9721 | capture */ |
9327 | break; | 9722 | break; |
9328 | default: | 9723 | default: |
9329 | spec->stream_name_analog = "ALC883 Analog"; | ||
9330 | spec->stream_name_digital = "ALC883 Digital"; | ||
9331 | if (!spec->num_adc_nids) { | 9724 | if (!spec->num_adc_nids) { |
9332 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); | 9725 | spec->num_adc_nids = ARRAY_SIZE(alc883_adc_nids); |
9333 | spec->adc_nids = alc883_adc_nids; | 9726 | spec->adc_nids = alc883_adc_nids; |
@@ -9407,24 +9800,6 @@ static struct snd_kcontrol_new alc262_base_mixer[] = { | |||
9407 | { } /* end */ | 9800 | { } /* end */ |
9408 | }; | 9801 | }; |
9409 | 9802 | ||
9410 | static struct snd_kcontrol_new alc262_hippo1_mixer[] = { | ||
9411 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
9412 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
9413 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
9414 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
9415 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
9416 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
9417 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
9418 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
9419 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
9420 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
9421 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
9422 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
9423 | /*HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0D, 0x0, HDA_OUTPUT),*/ | ||
9424 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
9425 | { } /* end */ | ||
9426 | }; | ||
9427 | |||
9428 | /* update HP, line and mono-out pins according to the master switch */ | 9803 | /* update HP, line and mono-out pins according to the master switch */ |
9429 | static void alc262_hp_master_update(struct hda_codec *codec) | 9804 | static void alc262_hp_master_update(struct hda_codec *codec) |
9430 | { | 9805 | { |
@@ -9480,14 +9855,7 @@ static void alc262_hp_wildwest_unsol_event(struct hda_codec *codec, | |||
9480 | alc262_hp_wildwest_automute(codec); | 9855 | alc262_hp_wildwest_automute(codec); |
9481 | } | 9856 | } |
9482 | 9857 | ||
9483 | static int alc262_hp_master_sw_get(struct snd_kcontrol *kcontrol, | 9858 | #define alc262_hp_master_sw_get alc260_hp_master_sw_get |
9484 | struct snd_ctl_elem_value *ucontrol) | ||
9485 | { | ||
9486 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
9487 | struct alc_spec *spec = codec->spec; | ||
9488 | *ucontrol->value.integer.value = spec->master_sw; | ||
9489 | return 0; | ||
9490 | } | ||
9491 | 9859 | ||
9492 | static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, | 9860 | static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, |
9493 | struct snd_ctl_elem_value *ucontrol) | 9861 | struct snd_ctl_elem_value *ucontrol) |
@@ -9503,14 +9871,17 @@ static int alc262_hp_master_sw_put(struct snd_kcontrol *kcontrol, | |||
9503 | return 1; | 9871 | return 1; |
9504 | } | 9872 | } |
9505 | 9873 | ||
9874 | #define ALC262_HP_MASTER_SWITCH \ | ||
9875 | { \ | ||
9876 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
9877 | .name = "Master Playback Switch", \ | ||
9878 | .info = snd_ctl_boolean_mono_info, \ | ||
9879 | .get = alc262_hp_master_sw_get, \ | ||
9880 | .put = alc262_hp_master_sw_put, \ | ||
9881 | } | ||
9882 | |||
9506 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | 9883 | static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { |
9507 | { | 9884 | ALC262_HP_MASTER_SWITCH, |
9508 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
9509 | .name = "Master Playback Switch", | ||
9510 | .info = snd_ctl_boolean_mono_info, | ||
9511 | .get = alc262_hp_master_sw_get, | ||
9512 | .put = alc262_hp_master_sw_put, | ||
9513 | }, | ||
9514 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 9885 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
9515 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 9886 | HDA_CODEC_MUTE("Front Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
9516 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 9887 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
@@ -9534,13 +9905,7 @@ static struct snd_kcontrol_new alc262_HP_BPC_mixer[] = { | |||
9534 | }; | 9905 | }; |
9535 | 9906 | ||
9536 | static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { | 9907 | static struct snd_kcontrol_new alc262_HP_BPC_WildWest_mixer[] = { |
9537 | { | 9908 | ALC262_HP_MASTER_SWITCH, |
9538 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
9539 | .name = "Master Playback Switch", | ||
9540 | .info = snd_ctl_boolean_mono_info, | ||
9541 | .get = alc262_hp_master_sw_get, | ||
9542 | .put = alc262_hp_master_sw_put, | ||
9543 | }, | ||
9544 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 9909 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
9545 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | 9910 | HDA_CODEC_MUTE("Front Playback Switch", 0x1b, 0x0, HDA_OUTPUT), |
9546 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | 9911 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), |
@@ -9567,32 +9932,13 @@ static struct snd_kcontrol_new alc262_HP_BPC_WildWest_option_mixer[] = { | |||
9567 | }; | 9932 | }; |
9568 | 9933 | ||
9569 | /* mute/unmute internal speaker according to the hp jack and mute state */ | 9934 | /* mute/unmute internal speaker according to the hp jack and mute state */ |
9570 | static void alc262_hp_t5735_automute(struct hda_codec *codec, int force) | 9935 | static void alc262_hp_t5735_init_hook(struct hda_codec *codec) |
9571 | { | 9936 | { |
9572 | struct alc_spec *spec = codec->spec; | 9937 | struct alc_spec *spec = codec->spec; |
9573 | 9938 | ||
9574 | if (force || !spec->sense_updated) { | 9939 | spec->autocfg.hp_pins[0] = 0x15; |
9575 | unsigned int present; | 9940 | spec->autocfg.speaker_pins[0] = 0x0c; /* HACK: not actually a pin */ |
9576 | present = snd_hda_codec_read(codec, 0x15, 0, | 9941 | alc_automute_amp(codec); |
9577 | AC_VERB_GET_PIN_SENSE, 0); | ||
9578 | spec->jack_present = (present & AC_PINSENSE_PRESENCE) != 0; | ||
9579 | spec->sense_updated = 1; | ||
9580 | } | ||
9581 | snd_hda_codec_amp_stereo(codec, 0x0c, HDA_OUTPUT, 0, HDA_AMP_MUTE, | ||
9582 | spec->jack_present ? HDA_AMP_MUTE : 0); | ||
9583 | } | ||
9584 | |||
9585 | static void alc262_hp_t5735_unsol_event(struct hda_codec *codec, | ||
9586 | unsigned int res) | ||
9587 | { | ||
9588 | if ((res >> 26) != ALC880_HP_EVENT) | ||
9589 | return; | ||
9590 | alc262_hp_t5735_automute(codec, 1); | ||
9591 | } | ||
9592 | |||
9593 | static void alc262_hp_t5735_init_hook(struct hda_codec *codec) | ||
9594 | { | ||
9595 | alc262_hp_t5735_automute(codec, 1); | ||
9596 | } | 9942 | } |
9597 | 9943 | ||
9598 | static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { | 9944 | static struct snd_kcontrol_new alc262_hp_t5735_mixer[] = { |
@@ -9645,46 +9991,132 @@ static struct hda_input_mux alc262_hp_rp5700_capture_source = { | |||
9645 | }, | 9991 | }, |
9646 | }; | 9992 | }; |
9647 | 9993 | ||
9648 | /* bind hp and internal speaker mute (with plug check) */ | 9994 | /* bind hp and internal speaker mute (with plug check) as master switch */ |
9649 | static int alc262_sony_master_sw_put(struct snd_kcontrol *kcontrol, | 9995 | static void alc262_hippo_master_update(struct hda_codec *codec) |
9650 | struct snd_ctl_elem_value *ucontrol) | ||
9651 | { | 9996 | { |
9652 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 9997 | struct alc_spec *spec = codec->spec; |
9653 | long *valp = ucontrol->value.integer.value; | 9998 | hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; |
9654 | int change; | 9999 | hda_nid_t line_nid = spec->autocfg.line_out_pins[0]; |
10000 | hda_nid_t speaker_nid = spec->autocfg.speaker_pins[0]; | ||
10001 | unsigned int mute; | ||
9655 | 10002 | ||
9656 | /* change hp mute */ | 10003 | /* HP */ |
9657 | change = snd_hda_codec_amp_update(codec, 0x15, 0, HDA_OUTPUT, 0, | 10004 | mute = spec->master_sw ? 0 : HDA_AMP_MUTE; |
9658 | HDA_AMP_MUTE, | 10005 | snd_hda_codec_amp_stereo(codec, hp_nid, HDA_OUTPUT, 0, |
9659 | valp[0] ? 0 : HDA_AMP_MUTE); | 10006 | HDA_AMP_MUTE, mute); |
9660 | change |= snd_hda_codec_amp_update(codec, 0x15, 1, HDA_OUTPUT, 0, | 10007 | /* mute internal speaker per jack sense */ |
9661 | HDA_AMP_MUTE, | 10008 | if (spec->jack_present) |
9662 | valp[1] ? 0 : HDA_AMP_MUTE); | 10009 | mute = HDA_AMP_MUTE; |
9663 | if (change) { | 10010 | if (line_nid) |
9664 | /* change speaker according to HP jack state */ | 10011 | snd_hda_codec_amp_stereo(codec, line_nid, HDA_OUTPUT, 0, |
9665 | struct alc_spec *spec = codec->spec; | ||
9666 | unsigned int mute; | ||
9667 | if (spec->jack_present) | ||
9668 | mute = HDA_AMP_MUTE; | ||
9669 | else | ||
9670 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, | ||
9671 | HDA_OUTPUT, 0); | ||
9672 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
9673 | HDA_AMP_MUTE, mute); | 10012 | HDA_AMP_MUTE, mute); |
10013 | if (speaker_nid && speaker_nid != line_nid) | ||
10014 | snd_hda_codec_amp_stereo(codec, speaker_nid, HDA_OUTPUT, 0, | ||
10015 | HDA_AMP_MUTE, mute); | ||
10016 | } | ||
10017 | |||
10018 | #define alc262_hippo_master_sw_get alc262_hp_master_sw_get | ||
10019 | |||
10020 | static int alc262_hippo_master_sw_put(struct snd_kcontrol *kcontrol, | ||
10021 | struct snd_ctl_elem_value *ucontrol) | ||
10022 | { | ||
10023 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
10024 | struct alc_spec *spec = codec->spec; | ||
10025 | int val = !!*ucontrol->value.integer.value; | ||
10026 | |||
10027 | if (val == spec->master_sw) | ||
10028 | return 0; | ||
10029 | spec->master_sw = val; | ||
10030 | alc262_hippo_master_update(codec); | ||
10031 | return 1; | ||
10032 | } | ||
10033 | |||
10034 | #define ALC262_HIPPO_MASTER_SWITCH \ | ||
10035 | { \ | ||
10036 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
10037 | .name = "Master Playback Switch", \ | ||
10038 | .info = snd_ctl_boolean_mono_info, \ | ||
10039 | .get = alc262_hippo_master_sw_get, \ | ||
10040 | .put = alc262_hippo_master_sw_put, \ | ||
9674 | } | 10041 | } |
9675 | return change; | 10042 | |
10043 | static struct snd_kcontrol_new alc262_hippo_mixer[] = { | ||
10044 | ALC262_HIPPO_MASTER_SWITCH, | ||
10045 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
10046 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
10047 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
10048 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
10049 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
10050 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
10051 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
10052 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
10053 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
10054 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
10055 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
10056 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x0d, 0x0, HDA_OUTPUT), | ||
10057 | { } /* end */ | ||
10058 | }; | ||
10059 | |||
10060 | static struct snd_kcontrol_new alc262_hippo1_mixer[] = { | ||
10061 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | ||
10062 | ALC262_HIPPO_MASTER_SWITCH, | ||
10063 | HDA_CODEC_VOLUME("CD Playback Volume", 0x0b, 0x04, HDA_INPUT), | ||
10064 | HDA_CODEC_MUTE("CD Playback Switch", 0x0b, 0x04, HDA_INPUT), | ||
10065 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | ||
10066 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | ||
10067 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
10068 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
10069 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
10070 | HDA_CODEC_VOLUME("Front Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | ||
10071 | HDA_CODEC_MUTE("Front Mic Playback Switch", 0x0b, 0x01, HDA_INPUT), | ||
10072 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
10073 | { } /* end */ | ||
10074 | }; | ||
10075 | |||
10076 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
10077 | static void alc262_hippo_automute(struct hda_codec *codec) | ||
10078 | { | ||
10079 | struct alc_spec *spec = codec->spec; | ||
10080 | hda_nid_t hp_nid = spec->autocfg.hp_pins[0]; | ||
10081 | unsigned int present; | ||
10082 | |||
10083 | /* need to execute and sync at first */ | ||
10084 | snd_hda_codec_read(codec, hp_nid, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
10085 | present = snd_hda_codec_read(codec, hp_nid, 0, | ||
10086 | AC_VERB_GET_PIN_SENSE, 0); | ||
10087 | spec->jack_present = (present & 0x80000000) != 0; | ||
10088 | alc262_hippo_master_update(codec); | ||
10089 | } | ||
10090 | |||
10091 | static void alc262_hippo_unsol_event(struct hda_codec *codec, unsigned int res) | ||
10092 | { | ||
10093 | if ((res >> 26) != ALC880_HP_EVENT) | ||
10094 | return; | ||
10095 | alc262_hippo_automute(codec); | ||
10096 | } | ||
10097 | |||
10098 | static void alc262_hippo_init_hook(struct hda_codec *codec) | ||
10099 | { | ||
10100 | struct alc_spec *spec = codec->spec; | ||
10101 | |||
10102 | spec->autocfg.hp_pins[0] = 0x15; | ||
10103 | spec->autocfg.speaker_pins[0] = 0x14; | ||
10104 | alc262_hippo_automute(codec); | ||
10105 | } | ||
10106 | |||
10107 | static void alc262_hippo1_init_hook(struct hda_codec *codec) | ||
10108 | { | ||
10109 | struct alc_spec *spec = codec->spec; | ||
10110 | |||
10111 | spec->autocfg.hp_pins[0] = 0x1b; | ||
10112 | spec->autocfg.speaker_pins[0] = 0x14; | ||
10113 | alc262_hippo_automute(codec); | ||
9676 | } | 10114 | } |
9677 | 10115 | ||
10116 | |||
9678 | static struct snd_kcontrol_new alc262_sony_mixer[] = { | 10117 | static struct snd_kcontrol_new alc262_sony_mixer[] = { |
9679 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 10118 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
9680 | { | 10119 | ALC262_HIPPO_MASTER_SWITCH, |
9681 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
9682 | .name = "Master Playback Switch", | ||
9683 | .info = snd_hda_mixer_amp_switch_info, | ||
9684 | .get = snd_hda_mixer_amp_switch_get, | ||
9685 | .put = alc262_sony_master_sw_put, | ||
9686 | .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), | ||
9687 | }, | ||
9688 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 10120 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
9689 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 10121 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
9690 | HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), | 10122 | HDA_CODEC_VOLUME("ATAPI Mic Playback Volume", 0x0b, 0x01, HDA_INPUT), |
@@ -9693,8 +10125,8 @@ static struct snd_kcontrol_new alc262_sony_mixer[] = { | |||
9693 | }; | 10125 | }; |
9694 | 10126 | ||
9695 | static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { | 10127 | static struct snd_kcontrol_new alc262_benq_t31_mixer[] = { |
9696 | HDA_CODEC_VOLUME("Front Playback Volume", 0x0c, 0x0, HDA_OUTPUT), | 10128 | HDA_CODEC_VOLUME("Master Playback Volume", 0x0c, 0x0, HDA_OUTPUT), |
9697 | HDA_CODEC_MUTE("Front Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 10129 | ALC262_HIPPO_MASTER_SWITCH, |
9698 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), | 10130 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x15, 0x0, HDA_OUTPUT), |
9699 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 10131 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
9700 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 10132 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
@@ -9735,34 +10167,15 @@ static struct hda_verb alc262_tyan_verbs[] = { | |||
9735 | }; | 10167 | }; |
9736 | 10168 | ||
9737 | /* unsolicited event for HP jack sensing */ | 10169 | /* unsolicited event for HP jack sensing */ |
9738 | static void alc262_tyan_automute(struct hda_codec *codec) | 10170 | static void alc262_tyan_init_hook(struct hda_codec *codec) |
9739 | { | 10171 | { |
9740 | unsigned int mute; | 10172 | struct alc_spec *spec = codec->spec; |
9741 | unsigned int present; | ||
9742 | 10173 | ||
9743 | snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); | 10174 | spec->autocfg.hp_pins[0] = 0x1b; |
9744 | present = snd_hda_codec_read(codec, 0x1b, 0, | 10175 | spec->autocfg.speaker_pins[0] = 0x15; |
9745 | AC_VERB_GET_PIN_SENSE, 0); | 10176 | alc_automute_amp(codec); |
9746 | present = (present & 0x80000000) != 0; | ||
9747 | if (present) { | ||
9748 | /* mute line output on ATX panel */ | ||
9749 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
9750 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
9751 | } else { | ||
9752 | /* unmute line output if necessary */ | ||
9753 | mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); | ||
9754 | snd_hda_codec_amp_stereo(codec, 0x15, HDA_OUTPUT, 0, | ||
9755 | HDA_AMP_MUTE, mute); | ||
9756 | } | ||
9757 | } | 10177 | } |
9758 | 10178 | ||
9759 | static void alc262_tyan_unsol_event(struct hda_codec *codec, | ||
9760 | unsigned int res) | ||
9761 | { | ||
9762 | if ((res >> 26) != ALC880_HP_EVENT) | ||
9763 | return; | ||
9764 | alc262_tyan_automute(codec); | ||
9765 | } | ||
9766 | 10179 | ||
9767 | #define alc262_capture_mixer alc882_capture_mixer | 10180 | #define alc262_capture_mixer alc882_capture_mixer |
9768 | #define alc262_capture_alt_mixer alc882_capture_alt_mixer | 10181 | #define alc262_capture_alt_mixer alc882_capture_alt_mixer |
@@ -9917,99 +10330,25 @@ static void alc262_dmic_automute(struct hda_codec *codec) | |||
9917 | AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09); | 10330 | AC_VERB_SET_CONNECT_SEL, present ? 0x0 : 0x09); |
9918 | } | 10331 | } |
9919 | 10332 | ||
9920 | /* toggle speaker-output according to the hp-jack state */ | ||
9921 | static void alc262_toshiba_s06_speaker_automute(struct hda_codec *codec) | ||
9922 | { | ||
9923 | unsigned int present; | ||
9924 | unsigned char bits; | ||
9925 | |||
9926 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
9927 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
9928 | bits = present ? 0 : PIN_OUT; | ||
9929 | snd_hda_codec_write(codec, 0x14, 0, | ||
9930 | AC_VERB_SET_PIN_WIDGET_CONTROL, bits); | ||
9931 | } | ||
9932 | |||
9933 | |||
9934 | 10333 | ||
9935 | /* unsolicited event for HP jack sensing */ | 10334 | /* unsolicited event for HP jack sensing */ |
9936 | static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec, | 10335 | static void alc262_toshiba_s06_unsol_event(struct hda_codec *codec, |
9937 | unsigned int res) | 10336 | unsigned int res) |
9938 | { | 10337 | { |
9939 | if ((res >> 26) == ALC880_HP_EVENT) | ||
9940 | alc262_toshiba_s06_speaker_automute(codec); | ||
9941 | if ((res >> 26) == ALC880_MIC_EVENT) | 10338 | if ((res >> 26) == ALC880_MIC_EVENT) |
9942 | alc262_dmic_automute(codec); | 10339 | alc262_dmic_automute(codec); |
9943 | 10340 | else | |
10341 | alc_sku_unsol_event(codec, res); | ||
9944 | } | 10342 | } |
9945 | 10343 | ||
9946 | static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) | 10344 | static void alc262_toshiba_s06_init_hook(struct hda_codec *codec) |
9947 | { | 10345 | { |
9948 | alc262_toshiba_s06_speaker_automute(codec); | ||
9949 | alc262_dmic_automute(codec); | ||
9950 | } | ||
9951 | |||
9952 | /* mute/unmute internal speaker according to the hp jack and mute state */ | ||
9953 | static void alc262_hippo_automute(struct hda_codec *codec) | ||
9954 | { | ||
9955 | struct alc_spec *spec = codec->spec; | 10346 | struct alc_spec *spec = codec->spec; |
9956 | unsigned int mute; | ||
9957 | unsigned int present; | ||
9958 | |||
9959 | /* need to execute and sync at first */ | ||
9960 | snd_hda_codec_read(codec, 0x15, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
9961 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
9962 | AC_VERB_GET_PIN_SENSE, 0); | ||
9963 | spec->jack_present = (present & 0x80000000) != 0; | ||
9964 | if (spec->jack_present) { | ||
9965 | /* mute internal speaker */ | ||
9966 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
9967 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
9968 | } else { | ||
9969 | /* unmute internal speaker if necessary */ | ||
9970 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); | ||
9971 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
9972 | HDA_AMP_MUTE, mute); | ||
9973 | } | ||
9974 | } | ||
9975 | |||
9976 | /* unsolicited event for HP jack sensing */ | ||
9977 | static void alc262_hippo_unsol_event(struct hda_codec *codec, | ||
9978 | unsigned int res) | ||
9979 | { | ||
9980 | if ((res >> 26) != ALC880_HP_EVENT) | ||
9981 | return; | ||
9982 | alc262_hippo_automute(codec); | ||
9983 | } | ||
9984 | |||
9985 | static void alc262_hippo1_automute(struct hda_codec *codec) | ||
9986 | { | ||
9987 | unsigned int mute; | ||
9988 | unsigned int present; | ||
9989 | 10347 | ||
9990 | snd_hda_codec_read(codec, 0x1b, 0, AC_VERB_SET_PIN_SENSE, 0); | 10348 | spec->autocfg.hp_pins[0] = 0x15; |
9991 | present = snd_hda_codec_read(codec, 0x1b, 0, | 10349 | spec->autocfg.speaker_pins[0] = 0x14; |
9992 | AC_VERB_GET_PIN_SENSE, 0); | 10350 | alc_automute_pin(codec); |
9993 | present = (present & 0x80000000) != 0; | 10351 | alc262_dmic_automute(codec); |
9994 | if (present) { | ||
9995 | /* mute internal speaker */ | ||
9996 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
9997 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
9998 | } else { | ||
9999 | /* unmute internal speaker if necessary */ | ||
10000 | mute = snd_hda_codec_amp_read(codec, 0x1b, 0, HDA_OUTPUT, 0); | ||
10001 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
10002 | HDA_AMP_MUTE, mute); | ||
10003 | } | ||
10004 | } | ||
10005 | |||
10006 | /* unsolicited event for HP jack sensing */ | ||
10007 | static void alc262_hippo1_unsol_event(struct hda_codec *codec, | ||
10008 | unsigned int res) | ||
10009 | { | ||
10010 | if ((res >> 26) != ALC880_HP_EVENT) | ||
10011 | return; | ||
10012 | alc262_hippo1_automute(codec); | ||
10013 | } | 10352 | } |
10014 | 10353 | ||
10015 | /* | 10354 | /* |
@@ -10279,14 +10618,7 @@ static struct snd_kcontrol_new alc262_lenovo_3000_mixer[] = { | |||
10279 | 10618 | ||
10280 | static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { | 10619 | static struct snd_kcontrol_new alc262_toshiba_rx1_mixer[] = { |
10281 | HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), | 10620 | HDA_BIND_VOL("Master Playback Volume", &alc262_fujitsu_bind_master_vol), |
10282 | { | 10621 | ALC262_HIPPO_MASTER_SWITCH, |
10283 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
10284 | .name = "Master Playback Switch", | ||
10285 | .info = snd_hda_mixer_amp_switch_info, | ||
10286 | .get = snd_hda_mixer_amp_switch_get, | ||
10287 | .put = alc262_sony_master_sw_put, | ||
10288 | .private_value = HDA_COMPOSE_AMP_VAL(0x15, 3, 0, HDA_OUTPUT), | ||
10289 | }, | ||
10290 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 10622 | HDA_CODEC_VOLUME("Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
10291 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | 10623 | HDA_CODEC_MUTE("Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), |
10292 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | 10624 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), |
@@ -10633,31 +10965,46 @@ static struct hda_verb alc262_HP_BPC_init_verbs[] = { | |||
10633 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 10965 | {0x1a, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, |
10634 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, | 10966 | {0x1c, AC_VERB_SET_PIN_WIDGET_CONTROL, 0x20}, |
10635 | 10967 | ||
10636 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, | 10968 | {0x14, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, |
10637 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, | 10969 | {0x18, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, |
10638 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, | 10970 | {0x19, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, |
10639 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7023 }, | 10971 | {0x1a, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, |
10640 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, | 10972 | {0x1c, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, |
10641 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, | 10973 | {0x1d, AC_VERB_SET_AMP_GAIN_MUTE, 0x7000 }, |
10642 | 10974 | ||
10643 | 10975 | ||
10644 | /* FIXME: use matrix-type input source selection */ | 10976 | /* FIXME: use matrix-type input source selection */ |
10645 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 16, 17, 0b */ | 10977 | /* Mixer elements: 0x18, 19, 1a, 1b, 1c, 1d, 14, 15, 0b, 12 */ |
10646 | /* Input mixer1: unmute Mic, F-Mic, Line, CD inputs */ | 10978 | /* Input mixer1: only unmute Mic */ |
10647 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 10979 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, |
10648 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | 10980 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, |
10649 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 10981 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, |
10650 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 10982 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, |
10983 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
10984 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, | ||
10985 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, | ||
10986 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, | ||
10987 | {0x24, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, | ||
10651 | /* Input mixer2 */ | 10988 | /* Input mixer2 */ |
10652 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 10989 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, |
10653 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | 10990 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, |
10654 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 10991 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, |
10655 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 10992 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, |
10993 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
10994 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, | ||
10995 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, | ||
10996 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, | ||
10997 | {0x23, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, | ||
10656 | /* Input mixer3 */ | 10998 | /* Input mixer3 */ |
10657 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, | 10999 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x00 << 8))}, |
10658 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x03 << 8))}, | 11000 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x01 << 8))}, |
10659 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x02 << 8))}, | 11001 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x02 << 8))}, |
10660 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7000 | (0x04 << 8))}, | 11002 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x03 << 8))}, |
11003 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x04 << 8))}, | ||
11004 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x05 << 8))}, | ||
11005 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x06 << 8))}, | ||
11006 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x07 << 8))}, | ||
11007 | {0x22, AC_VERB_SET_AMP_GAIN_MUTE, (0x7080 | (0x08 << 8))}, | ||
10661 | 11008 | ||
10662 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | 11009 | {0x1b, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, |
10663 | 11010 | ||
@@ -10837,6 +11184,8 @@ static int alc262_parse_auto_config(struct hda_codec *codec) | |||
10837 | if (err < 0) | 11184 | if (err < 0) |
10838 | return err; | 11185 | return err; |
10839 | 11186 | ||
11187 | alc_ssid_check(codec, 0x15, 0x14, 0x1b); | ||
11188 | |||
10840 | return 1; | 11189 | return 1; |
10841 | } | 11190 | } |
10842 | 11191 | ||
@@ -10939,7 +11288,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
10939 | .input_mux = &alc262_capture_source, | 11288 | .input_mux = &alc262_capture_source, |
10940 | }, | 11289 | }, |
10941 | [ALC262_HIPPO] = { | 11290 | [ALC262_HIPPO] = { |
10942 | .mixers = { alc262_base_mixer }, | 11291 | .mixers = { alc262_hippo_mixer }, |
10943 | .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, | 11292 | .init_verbs = { alc262_init_verbs, alc262_hippo_unsol_verbs}, |
10944 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), | 11293 | .num_dacs = ARRAY_SIZE(alc262_dac_nids), |
10945 | .dac_nids = alc262_dac_nids, | 11294 | .dac_nids = alc262_dac_nids, |
@@ -10949,7 +11298,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
10949 | .channel_mode = alc262_modes, | 11298 | .channel_mode = alc262_modes, |
10950 | .input_mux = &alc262_capture_source, | 11299 | .input_mux = &alc262_capture_source, |
10951 | .unsol_event = alc262_hippo_unsol_event, | 11300 | .unsol_event = alc262_hippo_unsol_event, |
10952 | .init_hook = alc262_hippo_automute, | 11301 | .init_hook = alc262_hippo_init_hook, |
10953 | }, | 11302 | }, |
10954 | [ALC262_HIPPO_1] = { | 11303 | [ALC262_HIPPO_1] = { |
10955 | .mixers = { alc262_hippo1_mixer }, | 11304 | .mixers = { alc262_hippo1_mixer }, |
@@ -10961,8 +11310,8 @@ static struct alc_config_preset alc262_presets[] = { | |||
10961 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 11310 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
10962 | .channel_mode = alc262_modes, | 11311 | .channel_mode = alc262_modes, |
10963 | .input_mux = &alc262_capture_source, | 11312 | .input_mux = &alc262_capture_source, |
10964 | .unsol_event = alc262_hippo1_unsol_event, | 11313 | .unsol_event = alc262_hippo_unsol_event, |
10965 | .init_hook = alc262_hippo1_automute, | 11314 | .init_hook = alc262_hippo1_init_hook, |
10966 | }, | 11315 | }, |
10967 | [ALC262_FUJITSU] = { | 11316 | [ALC262_FUJITSU] = { |
10968 | .mixers = { alc262_fujitsu_mixer }, | 11317 | .mixers = { alc262_fujitsu_mixer }, |
@@ -11024,7 +11373,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
11024 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 11373 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
11025 | .channel_mode = alc262_modes, | 11374 | .channel_mode = alc262_modes, |
11026 | .input_mux = &alc262_capture_source, | 11375 | .input_mux = &alc262_capture_source, |
11027 | .unsol_event = alc262_hp_t5735_unsol_event, | 11376 | .unsol_event = alc_automute_amp_unsol_event, |
11028 | .init_hook = alc262_hp_t5735_init_hook, | 11377 | .init_hook = alc262_hp_t5735_init_hook, |
11029 | }, | 11378 | }, |
11030 | [ALC262_HP_RP5700] = { | 11379 | [ALC262_HP_RP5700] = { |
@@ -11056,7 +11405,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
11056 | .channel_mode = alc262_modes, | 11405 | .channel_mode = alc262_modes, |
11057 | .input_mux = &alc262_capture_source, | 11406 | .input_mux = &alc262_capture_source, |
11058 | .unsol_event = alc262_hippo_unsol_event, | 11407 | .unsol_event = alc262_hippo_unsol_event, |
11059 | .init_hook = alc262_hippo_automute, | 11408 | .init_hook = alc262_hippo_init_hook, |
11060 | }, | 11409 | }, |
11061 | [ALC262_BENQ_T31] = { | 11410 | [ALC262_BENQ_T31] = { |
11062 | .mixers = { alc262_benq_t31_mixer }, | 11411 | .mixers = { alc262_benq_t31_mixer }, |
@@ -11068,7 +11417,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
11068 | .channel_mode = alc262_modes, | 11417 | .channel_mode = alc262_modes, |
11069 | .input_mux = &alc262_capture_source, | 11418 | .input_mux = &alc262_capture_source, |
11070 | .unsol_event = alc262_hippo_unsol_event, | 11419 | .unsol_event = alc262_hippo_unsol_event, |
11071 | .init_hook = alc262_hippo_automute, | 11420 | .init_hook = alc262_hippo_init_hook, |
11072 | }, | 11421 | }, |
11073 | [ALC262_ULTRA] = { | 11422 | [ALC262_ULTRA] = { |
11074 | .mixers = { alc262_ultra_mixer }, | 11423 | .mixers = { alc262_ultra_mixer }, |
@@ -11133,7 +11482,7 @@ static struct alc_config_preset alc262_presets[] = { | |||
11133 | .channel_mode = alc262_modes, | 11482 | .channel_mode = alc262_modes, |
11134 | .input_mux = &alc262_capture_source, | 11483 | .input_mux = &alc262_capture_source, |
11135 | .unsol_event = alc262_hippo_unsol_event, | 11484 | .unsol_event = alc262_hippo_unsol_event, |
11136 | .init_hook = alc262_hippo_automute, | 11485 | .init_hook = alc262_hippo_init_hook, |
11137 | }, | 11486 | }, |
11138 | [ALC262_TYAN] = { | 11487 | [ALC262_TYAN] = { |
11139 | .mixers = { alc262_tyan_mixer }, | 11488 | .mixers = { alc262_tyan_mixer }, |
@@ -11145,8 +11494,8 @@ static struct alc_config_preset alc262_presets[] = { | |||
11145 | .num_channel_mode = ARRAY_SIZE(alc262_modes), | 11494 | .num_channel_mode = ARRAY_SIZE(alc262_modes), |
11146 | .channel_mode = alc262_modes, | 11495 | .channel_mode = alc262_modes, |
11147 | .input_mux = &alc262_capture_source, | 11496 | .input_mux = &alc262_capture_source, |
11148 | .unsol_event = alc262_tyan_unsol_event, | 11497 | .unsol_event = alc_automute_amp_unsol_event, |
11149 | .init_hook = alc262_tyan_automute, | 11498 | .init_hook = alc262_tyan_init_hook, |
11150 | }, | 11499 | }, |
11151 | }; | 11500 | }; |
11152 | 11501 | ||
@@ -11181,8 +11530,8 @@ static int patch_alc262(struct hda_codec *codec) | |||
11181 | alc262_cfg_tbl); | 11530 | alc262_cfg_tbl); |
11182 | 11531 | ||
11183 | if (board_config < 0) { | 11532 | if (board_config < 0) { |
11184 | printk(KERN_INFO "hda_codec: Unknown model for ALC262, " | 11533 | printk(KERN_INFO "hda_codec: Unknown model for %s, " |
11185 | "trying auto-probe from BIOS...\n"); | 11534 | "trying auto-probe from BIOS...\n", codec->chip_name); |
11186 | board_config = ALC262_AUTO; | 11535 | board_config = ALC262_AUTO; |
11187 | } | 11536 | } |
11188 | 11537 | ||
@@ -11211,11 +11560,9 @@ static int patch_alc262(struct hda_codec *codec) | |||
11211 | if (board_config != ALC262_AUTO) | 11560 | if (board_config != ALC262_AUTO) |
11212 | setup_preset(spec, &alc262_presets[board_config]); | 11561 | setup_preset(spec, &alc262_presets[board_config]); |
11213 | 11562 | ||
11214 | spec->stream_name_analog = "ALC262 Analog"; | ||
11215 | spec->stream_analog_playback = &alc262_pcm_analog_playback; | 11563 | spec->stream_analog_playback = &alc262_pcm_analog_playback; |
11216 | spec->stream_analog_capture = &alc262_pcm_analog_capture; | 11564 | spec->stream_analog_capture = &alc262_pcm_analog_capture; |
11217 | 11565 | ||
11218 | spec->stream_name_digital = "ALC262 Digital"; | ||
11219 | spec->stream_digital_playback = &alc262_pcm_digital_playback; | 11566 | spec->stream_digital_playback = &alc262_pcm_digital_playback; |
11220 | spec->stream_digital_capture = &alc262_pcm_digital_capture; | 11567 | spec->stream_digital_capture = &alc262_pcm_digital_capture; |
11221 | 11568 | ||
@@ -11290,6 +11637,17 @@ static struct snd_kcontrol_new alc268_base_mixer[] = { | |||
11290 | { } | 11637 | { } |
11291 | }; | 11638 | }; |
11292 | 11639 | ||
11640 | static struct snd_kcontrol_new alc268_toshiba_mixer[] = { | ||
11641 | /* output mixer control */ | ||
11642 | HDA_CODEC_VOLUME("Front Playback Volume", 0x2, 0x0, HDA_OUTPUT), | ||
11643 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x3, 0x0, HDA_OUTPUT), | ||
11644 | ALC262_HIPPO_MASTER_SWITCH, | ||
11645 | HDA_CODEC_VOLUME("Mic Boost", 0x18, 0, HDA_INPUT), | ||
11646 | HDA_CODEC_VOLUME("Front Mic Boost", 0x19, 0, HDA_INPUT), | ||
11647 | HDA_CODEC_VOLUME("Line In Boost", 0x1a, 0, HDA_INPUT), | ||
11648 | { } | ||
11649 | }; | ||
11650 | |||
11293 | /* bind Beep switches of both NID 0x0f and 0x10 */ | 11651 | /* bind Beep switches of both NID 0x0f and 0x10 */ |
11294 | static struct hda_bind_ctls alc268_bind_beep_sw = { | 11652 | static struct hda_bind_ctls alc268_bind_beep_sw = { |
11295 | .ops = &snd_hda_bind_sw, | 11653 | .ops = &snd_hda_bind_sw, |
@@ -11313,8 +11671,6 @@ static struct hda_verb alc268_eapd_verbs[] = { | |||
11313 | }; | 11671 | }; |
11314 | 11672 | ||
11315 | /* Toshiba specific */ | 11673 | /* Toshiba specific */ |
11316 | #define alc268_toshiba_automute alc262_hippo_automute | ||
11317 | |||
11318 | static struct hda_verb alc268_toshiba_verbs[] = { | 11674 | static struct hda_verb alc268_toshiba_verbs[] = { |
11319 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, | 11675 | {0x15, AC_VERB_SET_UNSOLICITED_ENABLE, ALC880_HP_EVENT | AC_USRSP_EN}, |
11320 | { } /* end */ | 11676 | { } /* end */ |
@@ -11450,13 +11806,8 @@ static struct hda_verb alc268_acer_verbs[] = { | |||
11450 | }; | 11806 | }; |
11451 | 11807 | ||
11452 | /* unsolicited event for HP jack sensing */ | 11808 | /* unsolicited event for HP jack sensing */ |
11453 | static void alc268_toshiba_unsol_event(struct hda_codec *codec, | 11809 | #define alc268_toshiba_unsol_event alc262_hippo_unsol_event |
11454 | unsigned int res) | 11810 | #define alc268_toshiba_init_hook alc262_hippo_init_hook |
11455 | { | ||
11456 | if ((res >> 26) != ALC880_HP_EVENT) | ||
11457 | return; | ||
11458 | alc268_toshiba_automute(codec); | ||
11459 | } | ||
11460 | 11811 | ||
11461 | static void alc268_acer_unsol_event(struct hda_codec *codec, | 11812 | static void alc268_acer_unsol_event(struct hda_codec *codec, |
11462 | unsigned int res) | 11813 | unsigned int res) |
@@ -11531,30 +11882,15 @@ static struct hda_verb alc268_dell_verbs[] = { | |||
11531 | }; | 11882 | }; |
11532 | 11883 | ||
11533 | /* mute/unmute internal speaker according to the hp jack and mute state */ | 11884 | /* mute/unmute internal speaker according to the hp jack and mute state */ |
11534 | static void alc268_dell_automute(struct hda_codec *codec) | 11885 | static void alc268_dell_init_hook(struct hda_codec *codec) |
11535 | { | 11886 | { |
11536 | unsigned int present; | 11887 | struct alc_spec *spec = codec->spec; |
11537 | unsigned int mute; | ||
11538 | |||
11539 | present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0); | ||
11540 | if (present & 0x80000000) | ||
11541 | mute = HDA_AMP_MUTE; | ||
11542 | else | ||
11543 | mute = snd_hda_codec_amp_read(codec, 0x15, 0, HDA_OUTPUT, 0); | ||
11544 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
11545 | HDA_AMP_MUTE, mute); | ||
11546 | } | ||
11547 | 11888 | ||
11548 | static void alc268_dell_unsol_event(struct hda_codec *codec, | 11889 | spec->autocfg.hp_pins[0] = 0x15; |
11549 | unsigned int res) | 11890 | spec->autocfg.speaker_pins[0] = 0x14; |
11550 | { | 11891 | alc_automute_pin(codec); |
11551 | if ((res >> 26) != ALC880_HP_EVENT) | ||
11552 | return; | ||
11553 | alc268_dell_automute(codec); | ||
11554 | } | 11892 | } |
11555 | 11893 | ||
11556 | #define alc268_dell_init_hook alc268_dell_automute | ||
11557 | |||
11558 | static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { | 11894 | static struct snd_kcontrol_new alc267_quanta_il1_mixer[] = { |
11559 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), | 11895 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x2, 0x0, HDA_OUTPUT), |
11560 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 11896 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), |
@@ -11573,16 +11909,6 @@ static struct hda_verb alc267_quanta_il1_verbs[] = { | |||
11573 | { } | 11909 | { } |
11574 | }; | 11910 | }; |
11575 | 11911 | ||
11576 | static void alc267_quanta_il1_hp_automute(struct hda_codec *codec) | ||
11577 | { | ||
11578 | unsigned int present; | ||
11579 | |||
11580 | present = snd_hda_codec_read(codec, 0x15, 0, AC_VERB_GET_PIN_SENSE, 0) | ||
11581 | & AC_PINSENSE_PRESENCE; | ||
11582 | snd_hda_codec_write(codec, 0x14, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, | ||
11583 | present ? 0 : PIN_OUT); | ||
11584 | } | ||
11585 | |||
11586 | static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) | 11912 | static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) |
11587 | { | 11913 | { |
11588 | unsigned int present; | 11914 | unsigned int present; |
@@ -11594,9 +11920,13 @@ static void alc267_quanta_il1_mic_automute(struct hda_codec *codec) | |||
11594 | present ? 0x00 : 0x01); | 11920 | present ? 0x00 : 0x01); |
11595 | } | 11921 | } |
11596 | 11922 | ||
11597 | static void alc267_quanta_il1_automute(struct hda_codec *codec) | 11923 | static void alc267_quanta_il1_init_hook(struct hda_codec *codec) |
11598 | { | 11924 | { |
11599 | alc267_quanta_il1_hp_automute(codec); | 11925 | struct alc_spec *spec = codec->spec; |
11926 | |||
11927 | spec->autocfg.hp_pins[0] = 0x15; | ||
11928 | spec->autocfg.speaker_pins[0] = 0x14; | ||
11929 | alc_automute_pin(codec); | ||
11600 | alc267_quanta_il1_mic_automute(codec); | 11930 | alc267_quanta_il1_mic_automute(codec); |
11601 | } | 11931 | } |
11602 | 11932 | ||
@@ -11604,12 +11934,12 @@ static void alc267_quanta_il1_unsol_event(struct hda_codec *codec, | |||
11604 | unsigned int res) | 11934 | unsigned int res) |
11605 | { | 11935 | { |
11606 | switch (res >> 26) { | 11936 | switch (res >> 26) { |
11607 | case ALC880_HP_EVENT: | ||
11608 | alc267_quanta_il1_hp_automute(codec); | ||
11609 | break; | ||
11610 | case ALC880_MIC_EVENT: | 11937 | case ALC880_MIC_EVENT: |
11611 | alc267_quanta_il1_mic_automute(codec); | 11938 | alc267_quanta_il1_mic_automute(codec); |
11612 | break; | 11939 | break; |
11940 | default: | ||
11941 | alc_sku_unsol_event(codec, res); | ||
11942 | break; | ||
11613 | } | 11943 | } |
11614 | } | 11944 | } |
11615 | 11945 | ||
@@ -12057,15 +12387,16 @@ static struct snd_pci_quirk alc268_cfg_tbl[] = { | |||
12057 | ALC268_ACER_ASPIRE_ONE), | 12387 | ALC268_ACER_ASPIRE_ONE), |
12058 | SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), | 12388 | SND_PCI_QUIRK(0x1028, 0x0253, "Dell OEM", ALC268_DELL), |
12059 | SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL), | 12389 | SND_PCI_QUIRK(0x1028, 0x02b0, "Dell Inspiron Mini9", ALC268_DELL), |
12060 | SND_PCI_QUIRK(0x103c, 0x30cc, "TOSHIBA", ALC268_TOSHIBA), | 12390 | SND_PCI_QUIRK_MASK(0x103c, 0xff00, 0x3000, "HP TX25xx series", |
12391 | ALC268_TOSHIBA), | ||
12061 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), | 12392 | SND_PCI_QUIRK(0x1043, 0x1205, "ASUS W7J", ALC268_3ST), |
12062 | SND_PCI_QUIRK(0x1179, 0xff10, "TOSHIBA A205", ALC268_TOSHIBA), | 12393 | SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), |
12063 | SND_PCI_QUIRK(0x1179, 0xff50, "TOSHIBA A305", ALC268_TOSHIBA), | 12394 | SND_PCI_QUIRK_MASK(0x1179, 0xff00, 0xff00, "TOSHIBA A/Lx05", |
12064 | SND_PCI_QUIRK(0x1179, 0xff64, "TOSHIBA L305", ALC268_TOSHIBA), | 12395 | ALC268_TOSHIBA), |
12065 | SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), | 12396 | SND_PCI_QUIRK(0x14c0, 0x0025, "COMPAL IFL90/JFL-92", ALC268_TOSHIBA), |
12066 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), | 12397 | SND_PCI_QUIRK(0x152d, 0x0763, "Diverse (CPR2000)", ALC268_ACER), |
12067 | SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), | 12398 | SND_PCI_QUIRK(0x152d, 0x0771, "Quanta IL1", ALC267_QUANTA_IL1), |
12068 | SND_PCI_QUIRK(0x1170, 0x0040, "ZEPTO", ALC268_ZEPTO), | 12399 | SND_PCI_QUIRK(0x1854, 0x1775, "LG R510", ALC268_DELL), |
12069 | {} | 12400 | {} |
12070 | }; | 12401 | }; |
12071 | 12402 | ||
@@ -12083,7 +12414,7 @@ static struct alc_config_preset alc268_presets[] = { | |||
12083 | .channel_mode = alc268_modes, | 12414 | .channel_mode = alc268_modes, |
12084 | .input_mux = &alc268_capture_source, | 12415 | .input_mux = &alc268_capture_source, |
12085 | .unsol_event = alc267_quanta_il1_unsol_event, | 12416 | .unsol_event = alc267_quanta_il1_unsol_event, |
12086 | .init_hook = alc267_quanta_il1_automute, | 12417 | .init_hook = alc267_quanta_il1_init_hook, |
12087 | }, | 12418 | }, |
12088 | [ALC268_3ST] = { | 12419 | [ALC268_3ST] = { |
12089 | .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, | 12420 | .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, |
@@ -12101,7 +12432,7 @@ static struct alc_config_preset alc268_presets[] = { | |||
12101 | .input_mux = &alc268_capture_source, | 12432 | .input_mux = &alc268_capture_source, |
12102 | }, | 12433 | }, |
12103 | [ALC268_TOSHIBA] = { | 12434 | [ALC268_TOSHIBA] = { |
12104 | .mixers = { alc268_base_mixer, alc268_capture_alt_mixer, | 12435 | .mixers = { alc268_toshiba_mixer, alc268_capture_alt_mixer, |
12105 | alc268_beep_mixer }, | 12436 | alc268_beep_mixer }, |
12106 | .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, | 12437 | .init_verbs = { alc268_base_init_verbs, alc268_eapd_verbs, |
12107 | alc268_toshiba_verbs }, | 12438 | alc268_toshiba_verbs }, |
@@ -12115,7 +12446,7 @@ static struct alc_config_preset alc268_presets[] = { | |||
12115 | .channel_mode = alc268_modes, | 12446 | .channel_mode = alc268_modes, |
12116 | .input_mux = &alc268_capture_source, | 12447 | .input_mux = &alc268_capture_source, |
12117 | .unsol_event = alc268_toshiba_unsol_event, | 12448 | .unsol_event = alc268_toshiba_unsol_event, |
12118 | .init_hook = alc268_toshiba_automute, | 12449 | .init_hook = alc268_toshiba_init_hook, |
12119 | }, | 12450 | }, |
12120 | [ALC268_ACER] = { | 12451 | [ALC268_ACER] = { |
12121 | .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, | 12452 | .mixers = { alc268_acer_mixer, alc268_capture_alt_mixer, |
@@ -12178,7 +12509,7 @@ static struct alc_config_preset alc268_presets[] = { | |||
12178 | .hp_nid = 0x02, | 12509 | .hp_nid = 0x02, |
12179 | .num_channel_mode = ARRAY_SIZE(alc268_modes), | 12510 | .num_channel_mode = ARRAY_SIZE(alc268_modes), |
12180 | .channel_mode = alc268_modes, | 12511 | .channel_mode = alc268_modes, |
12181 | .unsol_event = alc268_dell_unsol_event, | 12512 | .unsol_event = alc_sku_unsol_event, |
12182 | .init_hook = alc268_dell_init_hook, | 12513 | .init_hook = alc268_dell_init_hook, |
12183 | .input_mux = &alc268_capture_source, | 12514 | .input_mux = &alc268_capture_source, |
12184 | }, | 12515 | }, |
@@ -12198,7 +12529,7 @@ static struct alc_config_preset alc268_presets[] = { | |||
12198 | .channel_mode = alc268_modes, | 12529 | .channel_mode = alc268_modes, |
12199 | .input_mux = &alc268_capture_source, | 12530 | .input_mux = &alc268_capture_source, |
12200 | .unsol_event = alc268_toshiba_unsol_event, | 12531 | .unsol_event = alc268_toshiba_unsol_event, |
12201 | .init_hook = alc268_toshiba_automute | 12532 | .init_hook = alc268_toshiba_init_hook |
12202 | }, | 12533 | }, |
12203 | #ifdef CONFIG_SND_DEBUG | 12534 | #ifdef CONFIG_SND_DEBUG |
12204 | [ALC268_TEST] = { | 12535 | [ALC268_TEST] = { |
@@ -12236,8 +12567,8 @@ static int patch_alc268(struct hda_codec *codec) | |||
12236 | alc268_cfg_tbl); | 12567 | alc268_cfg_tbl); |
12237 | 12568 | ||
12238 | if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { | 12569 | if (board_config < 0 || board_config >= ALC268_MODEL_LAST) { |
12239 | printk(KERN_INFO "hda_codec: Unknown model for ALC268, " | 12570 | printk(KERN_INFO "hda_codec: Unknown model for %s, " |
12240 | "trying auto-probe from BIOS...\n"); | 12571 | "trying auto-probe from BIOS...\n", codec->chip_name); |
12241 | board_config = ALC268_AUTO; | 12572 | board_config = ALC268_AUTO; |
12242 | } | 12573 | } |
12243 | 12574 | ||
@@ -12258,14 +12589,6 @@ static int patch_alc268(struct hda_codec *codec) | |||
12258 | if (board_config != ALC268_AUTO) | 12589 | if (board_config != ALC268_AUTO) |
12259 | setup_preset(spec, &alc268_presets[board_config]); | 12590 | setup_preset(spec, &alc268_presets[board_config]); |
12260 | 12591 | ||
12261 | if (codec->vendor_id == 0x10ec0267) { | ||
12262 | spec->stream_name_analog = "ALC267 Analog"; | ||
12263 | spec->stream_name_digital = "ALC267 Digital"; | ||
12264 | } else { | ||
12265 | spec->stream_name_analog = "ALC268 Analog"; | ||
12266 | spec->stream_name_digital = "ALC268 Digital"; | ||
12267 | } | ||
12268 | |||
12269 | spec->stream_analog_playback = &alc268_pcm_analog_playback; | 12592 | spec->stream_analog_playback = &alc268_pcm_analog_playback; |
12270 | spec->stream_analog_capture = &alc268_pcm_analog_capture; | 12593 | spec->stream_analog_capture = &alc268_pcm_analog_capture; |
12271 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; | 12594 | spec->stream_analog_alt_capture = &alc268_pcm_analog_alt_capture; |
@@ -13092,8 +13415,8 @@ static int patch_alc269(struct hda_codec *codec) | |||
13092 | alc269_cfg_tbl); | 13415 | alc269_cfg_tbl); |
13093 | 13416 | ||
13094 | if (board_config < 0) { | 13417 | if (board_config < 0) { |
13095 | printk(KERN_INFO "hda_codec: Unknown model for ALC269, " | 13418 | printk(KERN_INFO "hda_codec: Unknown model for %s, " |
13096 | "trying auto-probe from BIOS...\n"); | 13419 | "trying auto-probe from BIOS...\n", codec->chip_name); |
13097 | board_config = ALC269_AUTO; | 13420 | board_config = ALC269_AUTO; |
13098 | } | 13421 | } |
13099 | 13422 | ||
@@ -13120,7 +13443,6 @@ static int patch_alc269(struct hda_codec *codec) | |||
13120 | if (board_config != ALC269_AUTO) | 13443 | if (board_config != ALC269_AUTO) |
13121 | setup_preset(spec, &alc269_presets[board_config]); | 13444 | setup_preset(spec, &alc269_presets[board_config]); |
13122 | 13445 | ||
13123 | spec->stream_name_analog = "ALC269 Analog"; | ||
13124 | if (codec->subsystem_id == 0x17aa3bf8) { | 13446 | if (codec->subsystem_id == 0x17aa3bf8) { |
13125 | /* Due to a hardware problem on Lenovo Ideadpad, we need to | 13447 | /* Due to a hardware problem on Lenovo Ideadpad, we need to |
13126 | * fix the sample rate of analog I/O to 44.1kHz | 13448 | * fix the sample rate of analog I/O to 44.1kHz |
@@ -13131,7 +13453,6 @@ static int patch_alc269(struct hda_codec *codec) | |||
13131 | spec->stream_analog_playback = &alc269_pcm_analog_playback; | 13453 | spec->stream_analog_playback = &alc269_pcm_analog_playback; |
13132 | spec->stream_analog_capture = &alc269_pcm_analog_capture; | 13454 | spec->stream_analog_capture = &alc269_pcm_analog_capture; |
13133 | } | 13455 | } |
13134 | spec->stream_name_digital = "ALC269 Digital"; | ||
13135 | spec->stream_digital_playback = &alc269_pcm_digital_playback; | 13456 | spec->stream_digital_playback = &alc269_pcm_digital_playback; |
13136 | spec->stream_digital_capture = &alc269_pcm_digital_capture; | 13457 | spec->stream_digital_capture = &alc269_pcm_digital_capture; |
13137 | 13458 | ||
@@ -13920,7 +14241,6 @@ static void alc861_auto_init_multi_out(struct hda_codec *codec) | |||
13920 | struct alc_spec *spec = codec->spec; | 14241 | struct alc_spec *spec = codec->spec; |
13921 | int i; | 14242 | int i; |
13922 | 14243 | ||
13923 | alc_subsystem_id(codec, 0x0e, 0x0f, 0x0b); | ||
13924 | for (i = 0; i < spec->autocfg.line_outs; i++) { | 14244 | for (i = 0; i < spec->autocfg.line_outs; i++) { |
13925 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 14245 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
13926 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 14246 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -14003,6 +14323,8 @@ static int alc861_parse_auto_config(struct hda_codec *codec) | |||
14003 | spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); | 14323 | spec->num_adc_nids = ARRAY_SIZE(alc861_adc_nids); |
14004 | set_capture_mixer(spec); | 14324 | set_capture_mixer(spec); |
14005 | 14325 | ||
14326 | alc_ssid_check(codec, 0x0e, 0x0f, 0x0b); | ||
14327 | |||
14006 | return 1; | 14328 | return 1; |
14007 | } | 14329 | } |
14008 | 14330 | ||
@@ -14192,8 +14514,8 @@ static int patch_alc861(struct hda_codec *codec) | |||
14192 | alc861_cfg_tbl); | 14514 | alc861_cfg_tbl); |
14193 | 14515 | ||
14194 | if (board_config < 0) { | 14516 | if (board_config < 0) { |
14195 | printk(KERN_INFO "hda_codec: Unknown model for ALC861, " | 14517 | printk(KERN_INFO "hda_codec: Unknown model for %s, " |
14196 | "trying auto-probe from BIOS...\n"); | 14518 | "trying auto-probe from BIOS...\n", codec->chip_name); |
14197 | board_config = ALC861_AUTO; | 14519 | board_config = ALC861_AUTO; |
14198 | } | 14520 | } |
14199 | 14521 | ||
@@ -14220,11 +14542,9 @@ static int patch_alc861(struct hda_codec *codec) | |||
14220 | if (board_config != ALC861_AUTO) | 14542 | if (board_config != ALC861_AUTO) |
14221 | setup_preset(spec, &alc861_presets[board_config]); | 14543 | setup_preset(spec, &alc861_presets[board_config]); |
14222 | 14544 | ||
14223 | spec->stream_name_analog = "ALC861 Analog"; | ||
14224 | spec->stream_analog_playback = &alc861_pcm_analog_playback; | 14545 | spec->stream_analog_playback = &alc861_pcm_analog_playback; |
14225 | spec->stream_analog_capture = &alc861_pcm_analog_capture; | 14546 | spec->stream_analog_capture = &alc861_pcm_analog_capture; |
14226 | 14547 | ||
14227 | spec->stream_name_digital = "ALC861 Digital"; | ||
14228 | spec->stream_digital_playback = &alc861_pcm_digital_playback; | 14548 | spec->stream_digital_playback = &alc861_pcm_digital_playback; |
14229 | spec->stream_digital_capture = &alc861_pcm_digital_capture; | 14549 | spec->stream_digital_capture = &alc861_pcm_digital_capture; |
14230 | 14550 | ||
@@ -14611,19 +14931,6 @@ static struct hda_verb alc861vd_lenovo_unsol_verbs[] = { | |||
14611 | {} | 14931 | {} |
14612 | }; | 14932 | }; |
14613 | 14933 | ||
14614 | /* toggle speaker-output according to the hp-jack state */ | ||
14615 | static void alc861vd_lenovo_hp_automute(struct hda_codec *codec) | ||
14616 | { | ||
14617 | unsigned int present; | ||
14618 | unsigned char bits; | ||
14619 | |||
14620 | present = snd_hda_codec_read(codec, 0x1b, 0, | ||
14621 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
14622 | bits = present ? HDA_AMP_MUTE : 0; | ||
14623 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
14624 | HDA_AMP_MUTE, bits); | ||
14625 | } | ||
14626 | |||
14627 | static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) | 14934 | static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) |
14628 | { | 14935 | { |
14629 | unsigned int present; | 14936 | unsigned int present; |
@@ -14636,9 +14943,13 @@ static void alc861vd_lenovo_mic_automute(struct hda_codec *codec) | |||
14636 | HDA_AMP_MUTE, bits); | 14943 | HDA_AMP_MUTE, bits); |
14637 | } | 14944 | } |
14638 | 14945 | ||
14639 | static void alc861vd_lenovo_automute(struct hda_codec *codec) | 14946 | static void alc861vd_lenovo_init_hook(struct hda_codec *codec) |
14640 | { | 14947 | { |
14641 | alc861vd_lenovo_hp_automute(codec); | 14948 | struct alc_spec *spec = codec->spec; |
14949 | |||
14950 | spec->autocfg.hp_pins[0] = 0x1b; | ||
14951 | spec->autocfg.speaker_pins[0] = 0x14; | ||
14952 | alc_automute_amp(codec); | ||
14642 | alc861vd_lenovo_mic_automute(codec); | 14953 | alc861vd_lenovo_mic_automute(codec); |
14643 | } | 14954 | } |
14644 | 14955 | ||
@@ -14646,12 +14957,12 @@ static void alc861vd_lenovo_unsol_event(struct hda_codec *codec, | |||
14646 | unsigned int res) | 14957 | unsigned int res) |
14647 | { | 14958 | { |
14648 | switch (res >> 26) { | 14959 | switch (res >> 26) { |
14649 | case ALC880_HP_EVENT: | ||
14650 | alc861vd_lenovo_hp_automute(codec); | ||
14651 | break; | ||
14652 | case ALC880_MIC_EVENT: | 14960 | case ALC880_MIC_EVENT: |
14653 | alc861vd_lenovo_mic_automute(codec); | 14961 | alc861vd_lenovo_mic_automute(codec); |
14654 | break; | 14962 | break; |
14963 | default: | ||
14964 | alc_automute_amp_unsol_event(codec, res); | ||
14965 | break; | ||
14655 | } | 14966 | } |
14656 | } | 14967 | } |
14657 | 14968 | ||
@@ -14701,20 +15012,13 @@ static struct hda_verb alc861vd_dallas_verbs[] = { | |||
14701 | }; | 15012 | }; |
14702 | 15013 | ||
14703 | /* toggle speaker-output according to the hp-jack state */ | 15014 | /* toggle speaker-output according to the hp-jack state */ |
14704 | static void alc861vd_dallas_automute(struct hda_codec *codec) | 15015 | static void alc861vd_dallas_init_hook(struct hda_codec *codec) |
14705 | { | 15016 | { |
14706 | unsigned int present; | 15017 | struct alc_spec *spec = codec->spec; |
14707 | |||
14708 | present = snd_hda_codec_read(codec, 0x15, 0, | ||
14709 | AC_VERB_GET_PIN_SENSE, 0) & 0x80000000; | ||
14710 | snd_hda_codec_amp_stereo(codec, 0x14, HDA_OUTPUT, 0, | ||
14711 | HDA_AMP_MUTE, present ? HDA_AMP_MUTE : 0); | ||
14712 | } | ||
14713 | 15018 | ||
14714 | static void alc861vd_dallas_unsol_event(struct hda_codec *codec, unsigned int res) | 15019 | spec->autocfg.hp_pins[0] = 0x15; |
14715 | { | 15020 | spec->autocfg.speaker_pins[0] = 0x14; |
14716 | if ((res >> 26) == ALC880_HP_EVENT) | 15021 | alc_automute_amp(codec); |
14717 | alc861vd_dallas_automute(codec); | ||
14718 | } | 15022 | } |
14719 | 15023 | ||
14720 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 15024 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
@@ -14828,7 +15132,7 @@ static struct alc_config_preset alc861vd_presets[] = { | |||
14828 | .channel_mode = alc861vd_3stack_2ch_modes, | 15132 | .channel_mode = alc861vd_3stack_2ch_modes, |
14829 | .input_mux = &alc861vd_capture_source, | 15133 | .input_mux = &alc861vd_capture_source, |
14830 | .unsol_event = alc861vd_lenovo_unsol_event, | 15134 | .unsol_event = alc861vd_lenovo_unsol_event, |
14831 | .init_hook = alc861vd_lenovo_automute, | 15135 | .init_hook = alc861vd_lenovo_init_hook, |
14832 | }, | 15136 | }, |
14833 | [ALC861VD_DALLAS] = { | 15137 | [ALC861VD_DALLAS] = { |
14834 | .mixers = { alc861vd_dallas_mixer }, | 15138 | .mixers = { alc861vd_dallas_mixer }, |
@@ -14838,8 +15142,8 @@ static struct alc_config_preset alc861vd_presets[] = { | |||
14838 | .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), | 15142 | .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), |
14839 | .channel_mode = alc861vd_3stack_2ch_modes, | 15143 | .channel_mode = alc861vd_3stack_2ch_modes, |
14840 | .input_mux = &alc861vd_dallas_capture_source, | 15144 | .input_mux = &alc861vd_dallas_capture_source, |
14841 | .unsol_event = alc861vd_dallas_unsol_event, | 15145 | .unsol_event = alc_automute_amp_unsol_event, |
14842 | .init_hook = alc861vd_dallas_automute, | 15146 | .init_hook = alc861vd_dallas_init_hook, |
14843 | }, | 15147 | }, |
14844 | [ALC861VD_HP] = { | 15148 | [ALC861VD_HP] = { |
14845 | .mixers = { alc861vd_hp_mixer }, | 15149 | .mixers = { alc861vd_hp_mixer }, |
@@ -14850,8 +15154,8 @@ static struct alc_config_preset alc861vd_presets[] = { | |||
14850 | .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), | 15154 | .num_channel_mode = ARRAY_SIZE(alc861vd_3stack_2ch_modes), |
14851 | .channel_mode = alc861vd_3stack_2ch_modes, | 15155 | .channel_mode = alc861vd_3stack_2ch_modes, |
14852 | .input_mux = &alc861vd_hp_capture_source, | 15156 | .input_mux = &alc861vd_hp_capture_source, |
14853 | .unsol_event = alc861vd_dallas_unsol_event, | 15157 | .unsol_event = alc_automute_amp_unsol_event, |
14854 | .init_hook = alc861vd_dallas_automute, | 15158 | .init_hook = alc861vd_dallas_init_hook, |
14855 | }, | 15159 | }, |
14856 | [ALC660VD_ASUS_V1S] = { | 15160 | [ALC660VD_ASUS_V1S] = { |
14857 | .mixers = { alc861vd_lenovo_mixer }, | 15161 | .mixers = { alc861vd_lenovo_mixer }, |
@@ -14866,7 +15170,7 @@ static struct alc_config_preset alc861vd_presets[] = { | |||
14866 | .channel_mode = alc861vd_3stack_2ch_modes, | 15170 | .channel_mode = alc861vd_3stack_2ch_modes, |
14867 | .input_mux = &alc861vd_capture_source, | 15171 | .input_mux = &alc861vd_capture_source, |
14868 | .unsol_event = alc861vd_lenovo_unsol_event, | 15172 | .unsol_event = alc861vd_lenovo_unsol_event, |
14869 | .init_hook = alc861vd_lenovo_automute, | 15173 | .init_hook = alc861vd_lenovo_init_hook, |
14870 | }, | 15174 | }, |
14871 | }; | 15175 | }; |
14872 | 15176 | ||
@@ -14884,7 +15188,6 @@ static void alc861vd_auto_init_multi_out(struct hda_codec *codec) | |||
14884 | struct alc_spec *spec = codec->spec; | 15188 | struct alc_spec *spec = codec->spec; |
14885 | int i; | 15189 | int i; |
14886 | 15190 | ||
14887 | alc_subsystem_id(codec, 0x15, 0x1b, 0x14); | ||
14888 | for (i = 0; i <= HDA_SIDE; i++) { | 15191 | for (i = 0; i <= HDA_SIDE; i++) { |
14889 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 15192 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
14890 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 15193 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -15102,6 +15405,8 @@ static int alc861vd_parse_auto_config(struct hda_codec *codec) | |||
15102 | if (err < 0) | 15405 | if (err < 0) |
15103 | return err; | 15406 | return err; |
15104 | 15407 | ||
15408 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | ||
15409 | |||
15105 | return 1; | 15410 | return 1; |
15106 | } | 15411 | } |
15107 | 15412 | ||
@@ -15133,8 +15438,8 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
15133 | alc861vd_cfg_tbl); | 15438 | alc861vd_cfg_tbl); |
15134 | 15439 | ||
15135 | if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { | 15440 | if (board_config < 0 || board_config >= ALC861VD_MODEL_LAST) { |
15136 | printk(KERN_INFO "hda_codec: Unknown model for ALC660VD/" | 15441 | printk(KERN_INFO "hda_codec: Unknown model for %s, " |
15137 | "ALC861VD, trying auto-probe from BIOS...\n"); | 15442 | "trying auto-probe from BIOS...\n", codec->chip_name); |
15138 | board_config = ALC861VD_AUTO; | 15443 | board_config = ALC861VD_AUTO; |
15139 | } | 15444 | } |
15140 | 15445 | ||
@@ -15162,13 +15467,8 @@ static int patch_alc861vd(struct hda_codec *codec) | |||
15162 | setup_preset(spec, &alc861vd_presets[board_config]); | 15467 | setup_preset(spec, &alc861vd_presets[board_config]); |
15163 | 15468 | ||
15164 | if (codec->vendor_id == 0x10ec0660) { | 15469 | if (codec->vendor_id == 0x10ec0660) { |
15165 | spec->stream_name_analog = "ALC660-VD Analog"; | ||
15166 | spec->stream_name_digital = "ALC660-VD Digital"; | ||
15167 | /* always turn on EAPD */ | 15470 | /* always turn on EAPD */ |
15168 | add_verb(spec, alc660vd_eapd_verbs); | 15471 | add_verb(spec, alc660vd_eapd_verbs); |
15169 | } else { | ||
15170 | spec->stream_name_analog = "ALC861VD Analog"; | ||
15171 | spec->stream_name_digital = "ALC861VD Digital"; | ||
15172 | } | 15472 | } |
15173 | 15473 | ||
15174 | spec->stream_analog_playback = &alc861vd_pcm_analog_playback; | 15474 | spec->stream_analog_playback = &alc861vd_pcm_analog_playback; |
@@ -15282,6 +15582,38 @@ static struct hda_input_mux alc663_m51va_capture_source = { | |||
15282 | }, | 15582 | }, |
15283 | }; | 15583 | }; |
15284 | 15584 | ||
15585 | #if 1 /* set to 0 for testing other input sources below */ | ||
15586 | static struct hda_input_mux alc272_nc10_capture_source = { | ||
15587 | .num_items = 2, | ||
15588 | .items = { | ||
15589 | { "Autoselect Mic", 0x0 }, | ||
15590 | { "Internal Mic", 0x1 }, | ||
15591 | }, | ||
15592 | }; | ||
15593 | #else | ||
15594 | static struct hda_input_mux alc272_nc10_capture_source = { | ||
15595 | .num_items = 16, | ||
15596 | .items = { | ||
15597 | { "Autoselect Mic", 0x0 }, | ||
15598 | { "Internal Mic", 0x1 }, | ||
15599 | { "In-0x02", 0x2 }, | ||
15600 | { "In-0x03", 0x3 }, | ||
15601 | { "In-0x04", 0x4 }, | ||
15602 | { "In-0x05", 0x5 }, | ||
15603 | { "In-0x06", 0x6 }, | ||
15604 | { "In-0x07", 0x7 }, | ||
15605 | { "In-0x08", 0x8 }, | ||
15606 | { "In-0x09", 0x9 }, | ||
15607 | { "In-0x0a", 0x0a }, | ||
15608 | { "In-0x0b", 0x0b }, | ||
15609 | { "In-0x0c", 0x0c }, | ||
15610 | { "In-0x0d", 0x0d }, | ||
15611 | { "In-0x0e", 0x0e }, | ||
15612 | { "In-0x0f", 0x0f }, | ||
15613 | }, | ||
15614 | }; | ||
15615 | #endif | ||
15616 | |||
15285 | /* | 15617 | /* |
15286 | * 2ch mode | 15618 | * 2ch mode |
15287 | */ | 15619 | */ |
@@ -15421,10 +15753,8 @@ static struct snd_kcontrol_new alc662_lenovo_101e_mixer[] = { | |||
15421 | }; | 15753 | }; |
15422 | 15754 | ||
15423 | static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { | 15755 | static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { |
15424 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 15756 | HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
15425 | 15757 | ALC262_HIPPO_MASTER_SWITCH, | |
15426 | HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
15427 | HDA_CODEC_MUTE("Line-Out Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
15428 | 15758 | ||
15429 | HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), | 15759 | HDA_CODEC_VOLUME("e-Mic Boost", 0x18, 0, HDA_INPUT), |
15430 | HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | 15760 | HDA_CODEC_VOLUME("e-Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), |
@@ -15437,15 +15767,11 @@ static struct snd_kcontrol_new alc662_eeepc_p701_mixer[] = { | |||
15437 | }; | 15767 | }; |
15438 | 15768 | ||
15439 | static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { | 15769 | static struct snd_kcontrol_new alc662_eeepc_ep20_mixer[] = { |
15440 | HDA_CODEC_VOLUME("Line-Out Playback Volume", 0x02, 0x0, HDA_OUTPUT), | 15770 | ALC262_HIPPO_MASTER_SWITCH, |
15441 | HDA_CODEC_MUTE("Line-Out Playback Switch", 0x14, 0x0, HDA_OUTPUT), | 15771 | HDA_CODEC_VOLUME("Front Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
15442 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), | 15772 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x03, 0x0, HDA_OUTPUT), |
15443 | HDA_BIND_MUTE("Surround Playback Switch", 0x03, 2, HDA_INPUT), | ||
15444 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), | 15773 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x04, 1, 0x0, HDA_OUTPUT), |
15445 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), | 15774 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x04, 2, 0x0, HDA_OUTPUT), |
15446 | HDA_BIND_MUTE_MONO("Center Playback Switch", 0x04, 1, 2, HDA_INPUT), | ||
15447 | HDA_BIND_MUTE_MONO("LFE Playback Switch", 0x04, 2, 2, HDA_INPUT), | ||
15448 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x1b, 0x0, HDA_OUTPUT), | ||
15449 | HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), | 15775 | HDA_BIND_MUTE("MuteCtrl Playback Switch", 0x0c, 2, HDA_INPUT), |
15450 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), | 15776 | HDA_CODEC_VOLUME("Line Playback Volume", 0x0b, 0x02, HDA_INPUT), |
15451 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), | 15777 | HDA_CODEC_MUTE("Line Playback Switch", 0x0b, 0x02, HDA_INPUT), |
@@ -15953,51 +16279,25 @@ static void alc662_eeepc_mic_automute(struct hda_codec *codec) | |||
15953 | static void alc662_eeepc_unsol_event(struct hda_codec *codec, | 16279 | static void alc662_eeepc_unsol_event(struct hda_codec *codec, |
15954 | unsigned int res) | 16280 | unsigned int res) |
15955 | { | 16281 | { |
15956 | if ((res >> 26) == ALC880_HP_EVENT) | ||
15957 | alc262_hippo1_automute( codec ); | ||
15958 | |||
15959 | if ((res >> 26) == ALC880_MIC_EVENT) | 16282 | if ((res >> 26) == ALC880_MIC_EVENT) |
15960 | alc662_eeepc_mic_automute(codec); | 16283 | alc662_eeepc_mic_automute(codec); |
16284 | else | ||
16285 | alc262_hippo_unsol_event(codec, res); | ||
15961 | } | 16286 | } |
15962 | 16287 | ||
15963 | static void alc662_eeepc_inithook(struct hda_codec *codec) | 16288 | static void alc662_eeepc_inithook(struct hda_codec *codec) |
15964 | { | 16289 | { |
15965 | alc262_hippo1_automute( codec ); | 16290 | alc262_hippo1_init_hook(codec); |
15966 | alc662_eeepc_mic_automute(codec); | 16291 | alc662_eeepc_mic_automute(codec); |
15967 | } | 16292 | } |
15968 | 16293 | ||
15969 | static void alc662_eeepc_ep20_automute(struct hda_codec *codec) | ||
15970 | { | ||
15971 | unsigned int mute; | ||
15972 | unsigned int present; | ||
15973 | |||
15974 | snd_hda_codec_read(codec, 0x14, 0, AC_VERB_SET_PIN_SENSE, 0); | ||
15975 | present = snd_hda_codec_read(codec, 0x14, 0, | ||
15976 | AC_VERB_GET_PIN_SENSE, 0); | ||
15977 | present = (present & 0x80000000) != 0; | ||
15978 | if (present) { | ||
15979 | /* mute internal speaker */ | ||
15980 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
15981 | HDA_AMP_MUTE, HDA_AMP_MUTE); | ||
15982 | } else { | ||
15983 | /* unmute internal speaker if necessary */ | ||
15984 | mute = snd_hda_codec_amp_read(codec, 0x14, 0, HDA_OUTPUT, 0); | ||
15985 | snd_hda_codec_amp_stereo(codec, 0x1b, HDA_OUTPUT, 0, | ||
15986 | HDA_AMP_MUTE, mute); | ||
15987 | } | ||
15988 | } | ||
15989 | |||
15990 | /* unsolicited event for HP jack sensing */ | ||
15991 | static void alc662_eeepc_ep20_unsol_event(struct hda_codec *codec, | ||
15992 | unsigned int res) | ||
15993 | { | ||
15994 | if ((res >> 26) == ALC880_HP_EVENT) | ||
15995 | alc662_eeepc_ep20_automute(codec); | ||
15996 | } | ||
15997 | |||
15998 | static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) | 16294 | static void alc662_eeepc_ep20_inithook(struct hda_codec *codec) |
15999 | { | 16295 | { |
16000 | alc662_eeepc_ep20_automute(codec); | 16296 | struct alc_spec *spec = codec->spec; |
16297 | |||
16298 | spec->autocfg.hp_pins[0] = 0x14; | ||
16299 | spec->autocfg.speaker_pins[0] = 0x1b; | ||
16300 | alc262_hippo_master_update(codec); | ||
16001 | } | 16301 | } |
16002 | 16302 | ||
16003 | static void alc663_m51va_speaker_automute(struct hda_codec *codec) | 16303 | static void alc663_m51va_speaker_automute(struct hda_codec *codec) |
@@ -16331,35 +16631,9 @@ static void alc663_g50v_inithook(struct hda_codec *codec) | |||
16331 | alc662_eeepc_mic_automute(codec); | 16631 | alc662_eeepc_mic_automute(codec); |
16332 | } | 16632 | } |
16333 | 16633 | ||
16334 | /* bind hp and internal speaker mute (with plug check) */ | ||
16335 | static int alc662_ecs_master_sw_put(struct snd_kcontrol *kcontrol, | ||
16336 | struct snd_ctl_elem_value *ucontrol) | ||
16337 | { | ||
16338 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
16339 | long *valp = ucontrol->value.integer.value; | ||
16340 | int change; | ||
16341 | |||
16342 | change = snd_hda_codec_amp_update(codec, 0x1b, 0, HDA_OUTPUT, 0, | ||
16343 | HDA_AMP_MUTE, | ||
16344 | valp[0] ? 0 : HDA_AMP_MUTE); | ||
16345 | change |= snd_hda_codec_amp_update(codec, 0x1b, 1, HDA_OUTPUT, 0, | ||
16346 | HDA_AMP_MUTE, | ||
16347 | valp[1] ? 0 : HDA_AMP_MUTE); | ||
16348 | if (change) | ||
16349 | alc262_hippo1_automute(codec); | ||
16350 | return change; | ||
16351 | } | ||
16352 | |||
16353 | static struct snd_kcontrol_new alc662_ecs_mixer[] = { | 16634 | static struct snd_kcontrol_new alc662_ecs_mixer[] = { |
16354 | HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), | 16635 | HDA_CODEC_VOLUME("Master Playback Volume", 0x02, 0x0, HDA_OUTPUT), |
16355 | { | 16636 | ALC262_HIPPO_MASTER_SWITCH, |
16356 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
16357 | .name = "Master Playback Switch", | ||
16358 | .info = snd_hda_mixer_amp_switch_info, | ||
16359 | .get = snd_hda_mixer_amp_switch_get, | ||
16360 | .put = alc662_ecs_master_sw_put, | ||
16361 | .private_value = HDA_COMPOSE_AMP_VAL(0x1b, 3, 0, HDA_OUTPUT), | ||
16362 | }, | ||
16363 | 16637 | ||
16364 | HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT), | 16638 | HDA_CODEC_VOLUME("e-Mic/LineIn Boost", 0x18, 0, HDA_INPUT), |
16365 | HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), | 16639 | HDA_CODEC_VOLUME("e-Mic/LineIn Playback Volume", 0x0b, 0x0, HDA_INPUT), |
@@ -16371,6 +16645,23 @@ static struct snd_kcontrol_new alc662_ecs_mixer[] = { | |||
16371 | { } /* end */ | 16645 | { } /* end */ |
16372 | }; | 16646 | }; |
16373 | 16647 | ||
16648 | static struct snd_kcontrol_new alc272_nc10_mixer[] = { | ||
16649 | /* Master Playback automatically created from Speaker and Headphone */ | ||
16650 | HDA_CODEC_VOLUME("Speaker Playback Volume", 0x02, 0x0, HDA_OUTPUT), | ||
16651 | HDA_CODEC_MUTE("Speaker Playback Switch", 0x14, 0x0, HDA_OUTPUT), | ||
16652 | HDA_CODEC_VOLUME("Headphone Playback Volume", 0x03, 0x0, HDA_OUTPUT), | ||
16653 | HDA_CODEC_MUTE("Headphone Playback Switch", 0x21, 0x0, HDA_OUTPUT), | ||
16654 | |||
16655 | HDA_CODEC_VOLUME("Ext Mic Playback Volume", 0x0b, 0x0, HDA_INPUT), | ||
16656 | HDA_CODEC_MUTE("Ext Mic Playback Switch", 0x0b, 0x0, HDA_INPUT), | ||
16657 | HDA_CODEC_VOLUME("Ext Mic Boost", 0x18, 0, HDA_INPUT), | ||
16658 | |||
16659 | HDA_CODEC_VOLUME("Int Mic Playback Volume", 0x0b, 0x1, HDA_INPUT), | ||
16660 | HDA_CODEC_MUTE("Int Mic Playback Switch", 0x0b, 0x1, HDA_INPUT), | ||
16661 | HDA_CODEC_VOLUME("Int Mic Boost", 0x19, 0, HDA_INPUT), | ||
16662 | { } /* end */ | ||
16663 | }; | ||
16664 | |||
16374 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 16665 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
16375 | #define alc662_loopbacks alc880_loopbacks | 16666 | #define alc662_loopbacks alc880_loopbacks |
16376 | #endif | 16667 | #endif |
@@ -16404,6 +16695,9 @@ static const char *alc662_models[ALC662_MODEL_LAST] = { | |||
16404 | [ALC663_ASUS_MODE4] = "asus-mode4", | 16695 | [ALC663_ASUS_MODE4] = "asus-mode4", |
16405 | [ALC663_ASUS_MODE5] = "asus-mode5", | 16696 | [ALC663_ASUS_MODE5] = "asus-mode5", |
16406 | [ALC663_ASUS_MODE6] = "asus-mode6", | 16697 | [ALC663_ASUS_MODE6] = "asus-mode6", |
16698 | [ALC272_DELL] = "dell", | ||
16699 | [ALC272_DELL_ZM1] = "dell-zm1", | ||
16700 | [ALC272_SAMSUNG_NC10] = "samsung-nc10", | ||
16407 | [ALC662_AUTO] = "auto", | 16701 | [ALC662_AUTO] = "auto", |
16408 | }; | 16702 | }; |
16409 | 16703 | ||
@@ -16461,6 +16755,7 @@ static struct snd_pci_quirk alc662_cfg_tbl[] = { | |||
16461 | SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), | 16755 | SND_PCI_QUIRK(0x105b, 0x0cd6, "Foxconn", ALC662_ECS), |
16462 | SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", | 16756 | SND_PCI_QUIRK(0x105b, 0x0d47, "Foxconn 45CMX/45GMX/45CMX-K", |
16463 | ALC662_3ST_6ch_DIG), | 16757 | ALC662_3ST_6ch_DIG), |
16758 | SND_PCI_QUIRK(0x144d, 0xca00, "Samsung NC10", ALC272_SAMSUNG_NC10), | ||
16464 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", | 16759 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte 945GCM-S2L", |
16465 | ALC662_3ST_6ch_DIG), | 16760 | ALC662_3ST_6ch_DIG), |
16466 | SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), | 16761 | SND_PCI_QUIRK(0x1565, 0x820f, "Biostar TA780G M2+", ALC662_3ST_6ch_DIG), |
@@ -16551,7 +16846,7 @@ static struct alc_config_preset alc662_presets[] = { | |||
16551 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), | 16846 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_6ch_modes), |
16552 | .channel_mode = alc662_3ST_6ch_modes, | 16847 | .channel_mode = alc662_3ST_6ch_modes, |
16553 | .input_mux = &alc662_lenovo_101e_capture_source, | 16848 | .input_mux = &alc662_lenovo_101e_capture_source, |
16554 | .unsol_event = alc662_eeepc_ep20_unsol_event, | 16849 | .unsol_event = alc662_eeepc_unsol_event, |
16555 | .init_hook = alc662_eeepc_ep20_inithook, | 16850 | .init_hook = alc662_eeepc_ep20_inithook, |
16556 | }, | 16851 | }, |
16557 | [ALC662_ECS] = { | 16852 | [ALC662_ECS] = { |
@@ -16732,6 +17027,18 @@ static struct alc_config_preset alc662_presets[] = { | |||
16732 | .unsol_event = alc663_m51va_unsol_event, | 17027 | .unsol_event = alc663_m51va_unsol_event, |
16733 | .init_hook = alc663_m51va_inithook, | 17028 | .init_hook = alc663_m51va_inithook, |
16734 | }, | 17029 | }, |
17030 | [ALC272_SAMSUNG_NC10] = { | ||
17031 | .mixers = { alc272_nc10_mixer }, | ||
17032 | .init_verbs = { alc662_init_verbs, | ||
17033 | alc663_21jd_amic_init_verbs }, | ||
17034 | .num_dacs = ARRAY_SIZE(alc272_dac_nids), | ||
17035 | .dac_nids = alc272_dac_nids, | ||
17036 | .num_channel_mode = ARRAY_SIZE(alc662_3ST_2ch_modes), | ||
17037 | .channel_mode = alc662_3ST_2ch_modes, | ||
17038 | .input_mux = &alc272_nc10_capture_source, | ||
17039 | .unsol_event = alc663_mode4_unsol_event, | ||
17040 | .init_hook = alc663_mode4_inithook, | ||
17041 | }, | ||
16735 | }; | 17042 | }; |
16736 | 17043 | ||
16737 | 17044 | ||
@@ -16926,7 +17233,6 @@ static void alc662_auto_init_multi_out(struct hda_codec *codec) | |||
16926 | struct alc_spec *spec = codec->spec; | 17233 | struct alc_spec *spec = codec->spec; |
16927 | int i; | 17234 | int i; |
16928 | 17235 | ||
16929 | alc_subsystem_id(codec, 0x15, 0x1b, 0x14); | ||
16930 | for (i = 0; i <= HDA_SIDE; i++) { | 17236 | for (i = 0; i <= HDA_SIDE; i++) { |
16931 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; | 17237 | hda_nid_t nid = spec->autocfg.line_out_pins[i]; |
16932 | int pin_type = get_pin_type(spec->autocfg.line_out_type); | 17238 | int pin_type = get_pin_type(spec->autocfg.line_out_type); |
@@ -17023,6 +17329,8 @@ static int alc662_parse_auto_config(struct hda_codec *codec) | |||
17023 | if (err < 0) | 17329 | if (err < 0) |
17024 | return err; | 17330 | return err; |
17025 | 17331 | ||
17332 | alc_ssid_check(codec, 0x15, 0x1b, 0x14); | ||
17333 | |||
17026 | return 1; | 17334 | return 1; |
17027 | } | 17335 | } |
17028 | 17336 | ||
@@ -17055,8 +17363,8 @@ static int patch_alc662(struct hda_codec *codec) | |||
17055 | alc662_models, | 17363 | alc662_models, |
17056 | alc662_cfg_tbl); | 17364 | alc662_cfg_tbl); |
17057 | if (board_config < 0) { | 17365 | if (board_config < 0) { |
17058 | printk(KERN_INFO "hda_codec: Unknown model for ALC662, " | 17366 | printk(KERN_INFO "hda_codec: Unknown model for %s, " |
17059 | "trying auto-probe from BIOS...\n"); | 17367 | "trying auto-probe from BIOS...\n", codec->chip_name); |
17060 | board_config = ALC662_AUTO; | 17368 | board_config = ALC662_AUTO; |
17061 | } | 17369 | } |
17062 | 17370 | ||
@@ -17083,17 +17391,6 @@ static int patch_alc662(struct hda_codec *codec) | |||
17083 | if (board_config != ALC662_AUTO) | 17391 | if (board_config != ALC662_AUTO) |
17084 | setup_preset(spec, &alc662_presets[board_config]); | 17392 | setup_preset(spec, &alc662_presets[board_config]); |
17085 | 17393 | ||
17086 | if (codec->vendor_id == 0x10ec0663) { | ||
17087 | spec->stream_name_analog = "ALC663 Analog"; | ||
17088 | spec->stream_name_digital = "ALC663 Digital"; | ||
17089 | } else if (codec->vendor_id == 0x10ec0272) { | ||
17090 | spec->stream_name_analog = "ALC272 Analog"; | ||
17091 | spec->stream_name_digital = "ALC272 Digital"; | ||
17092 | } else { | ||
17093 | spec->stream_name_analog = "ALC662 Analog"; | ||
17094 | spec->stream_name_digital = "ALC662 Digital"; | ||
17095 | } | ||
17096 | |||
17097 | spec->stream_analog_playback = &alc662_pcm_analog_playback; | 17394 | spec->stream_analog_playback = &alc662_pcm_analog_playback; |
17098 | spec->stream_analog_capture = &alc662_pcm_analog_capture; | 17395 | spec->stream_analog_capture = &alc662_pcm_analog_capture; |
17099 | 17396 | ||
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 917bc5d3ac2c..93e47c96a38b 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -100,6 +100,7 @@ enum { | |||
100 | STAC_HP_M4, | 100 | STAC_HP_M4, |
101 | STAC_HP_DV5, | 101 | STAC_HP_DV5, |
102 | STAC_HP_HDX, | 102 | STAC_HP_HDX, |
103 | STAC_HP_DV4_1222NR, | ||
103 | STAC_92HD71BXX_MODELS | 104 | STAC_92HD71BXX_MODELS |
104 | }; | 105 | }; |
105 | 106 | ||
@@ -150,6 +151,7 @@ enum { | |||
150 | STAC_D965_REF, | 151 | STAC_D965_REF, |
151 | STAC_D965_3ST, | 152 | STAC_D965_3ST, |
152 | STAC_D965_5ST, | 153 | STAC_D965_5ST, |
154 | STAC_D965_5ST_NO_FP, | ||
153 | STAC_DELL_3ST, | 155 | STAC_DELL_3ST, |
154 | STAC_DELL_BIOS, | 156 | STAC_DELL_BIOS, |
155 | STAC_927X_MODELS | 157 | STAC_927X_MODELS |
@@ -192,6 +194,7 @@ struct sigmatel_spec { | |||
192 | unsigned int gpio_dir; | 194 | unsigned int gpio_dir; |
193 | unsigned int gpio_data; | 195 | unsigned int gpio_data; |
194 | unsigned int gpio_mute; | 196 | unsigned int gpio_mute; |
197 | unsigned int gpio_led; | ||
195 | 198 | ||
196 | /* stream */ | 199 | /* stream */ |
197 | unsigned int stream_delay; | 200 | unsigned int stream_delay; |
@@ -633,6 +636,40 @@ static int stac92xx_smux_enum_put(struct snd_kcontrol *kcontrol, | |||
633 | return 0; | 636 | return 0; |
634 | } | 637 | } |
635 | 638 | ||
639 | static unsigned int stac92xx_vref_set(struct hda_codec *codec, | ||
640 | hda_nid_t nid, unsigned int new_vref) | ||
641 | { | ||
642 | unsigned int error; | ||
643 | unsigned int pincfg; | ||
644 | pincfg = snd_hda_codec_read(codec, nid, 0, | ||
645 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
646 | |||
647 | pincfg &= 0xff; | ||
648 | pincfg &= ~(AC_PINCTL_VREFEN | AC_PINCTL_IN_EN | AC_PINCTL_OUT_EN); | ||
649 | pincfg |= new_vref; | ||
650 | |||
651 | if (new_vref == AC_PINCTL_VREF_HIZ) | ||
652 | pincfg |= AC_PINCTL_OUT_EN; | ||
653 | else | ||
654 | pincfg |= AC_PINCTL_IN_EN; | ||
655 | |||
656 | error = snd_hda_codec_write_cache(codec, nid, 0, | ||
657 | AC_VERB_SET_PIN_WIDGET_CONTROL, pincfg); | ||
658 | if (error < 0) | ||
659 | return error; | ||
660 | else | ||
661 | return 1; | ||
662 | } | ||
663 | |||
664 | static unsigned int stac92xx_vref_get(struct hda_codec *codec, hda_nid_t nid) | ||
665 | { | ||
666 | unsigned int vref; | ||
667 | vref = snd_hda_codec_read(codec, nid, 0, | ||
668 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
669 | vref &= AC_PINCTL_VREFEN; | ||
670 | return vref; | ||
671 | } | ||
672 | |||
636 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 673 | static int stac92xx_mux_enum_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
637 | { | 674 | { |
638 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 675 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
@@ -994,6 +1031,17 @@ static struct hda_verb stac9205_core_init[] = { | |||
994 | .private_value = verb_read | (verb_write << 16), \ | 1031 | .private_value = verb_read | (verb_write << 16), \ |
995 | } | 1032 | } |
996 | 1033 | ||
1034 | #define DC_BIAS(xname, idx, nid) \ | ||
1035 | { \ | ||
1036 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
1037 | .name = xname, \ | ||
1038 | .index = idx, \ | ||
1039 | .info = stac92xx_dc_bias_info, \ | ||
1040 | .get = stac92xx_dc_bias_get, \ | ||
1041 | .put = stac92xx_dc_bias_put, \ | ||
1042 | .private_value = nid, \ | ||
1043 | } | ||
1044 | |||
997 | static struct snd_kcontrol_new stac9200_mixer[] = { | 1045 | static struct snd_kcontrol_new stac9200_mixer[] = { |
998 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), | 1046 | HDA_CODEC_VOLUME("Master Playback Volume", 0xb, 0, HDA_OUTPUT), |
999 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), | 1047 | HDA_CODEC_MUTE("Master Playback Switch", 0xb, 0, HDA_OUTPUT), |
@@ -1542,6 +1590,8 @@ static struct snd_pci_quirk stac9200_cfg_tbl[] = { | |||
1542 | /* SigmaTel reference board */ | 1590 | /* SigmaTel reference board */ |
1543 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, | 1591 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0x2668, |
1544 | "DFI LanParty", STAC_REF), | 1592 | "DFI LanParty", STAC_REF), |
1593 | SND_PCI_QUIRK(PCI_VENDOR_ID_INTEL, 0xfb30, | ||
1594 | "SigmaTel",STAC_9205_REF), | ||
1545 | SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, | 1595 | SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, |
1546 | "DFI LanParty", STAC_REF), | 1596 | "DFI LanParty", STAC_REF), |
1547 | /* Dell laptops have BIOS problem */ | 1597 | /* Dell laptops have BIOS problem */ |
@@ -1836,6 +1886,7 @@ static unsigned int *stac92hd71bxx_brd_tbl[STAC_92HD71BXX_MODELS] = { | |||
1836 | [STAC_HP_M4] = NULL, | 1886 | [STAC_HP_M4] = NULL, |
1837 | [STAC_HP_DV5] = NULL, | 1887 | [STAC_HP_DV5] = NULL, |
1838 | [STAC_HP_HDX] = NULL, | 1888 | [STAC_HP_HDX] = NULL, |
1889 | [STAC_HP_DV4_1222NR] = NULL, | ||
1839 | }; | 1890 | }; |
1840 | 1891 | ||
1841 | static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { | 1892 | static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { |
@@ -1847,6 +1898,7 @@ static const char *stac92hd71bxx_models[STAC_92HD71BXX_MODELS] = { | |||
1847 | [STAC_HP_M4] = "hp-m4", | 1898 | [STAC_HP_M4] = "hp-m4", |
1848 | [STAC_HP_DV5] = "hp-dv5", | 1899 | [STAC_HP_DV5] = "hp-dv5", |
1849 | [STAC_HP_HDX] = "hp-hdx", | 1900 | [STAC_HP_HDX] = "hp-hdx", |
1901 | [STAC_HP_DV4_1222NR] = "hp-dv4-1222nr", | ||
1850 | }; | 1902 | }; |
1851 | 1903 | ||
1852 | static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { | 1904 | static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { |
@@ -1855,6 +1907,8 @@ static struct snd_pci_quirk stac92hd71bxx_cfg_tbl[] = { | |||
1855 | "DFI LanParty", STAC_92HD71BXX_REF), | 1907 | "DFI LanParty", STAC_92HD71BXX_REF), |
1856 | SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, | 1908 | SND_PCI_QUIRK(PCI_VENDOR_ID_DFI, 0x3101, |
1857 | "DFI LanParty", STAC_92HD71BXX_REF), | 1909 | "DFI LanParty", STAC_92HD71BXX_REF), |
1910 | SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x30fb, | ||
1911 | "HP dv4-1222nr", STAC_HP_DV4_1222NR), | ||
1858 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, | 1912 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x3080, |
1859 | "HP", STAC_HP_DV5), | 1913 | "HP", STAC_HP_DV5), |
1860 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, | 1914 | SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xfff0, 0x30f0, |
@@ -2154,6 +2208,13 @@ static unsigned int d965_5st_pin_configs[14] = { | |||
2154 | 0x40000100, 0x40000100 | 2208 | 0x40000100, 0x40000100 |
2155 | }; | 2209 | }; |
2156 | 2210 | ||
2211 | static unsigned int d965_5st_no_fp_pin_configs[14] = { | ||
2212 | 0x40000100, 0x40000100, 0x0181304e, 0x01014010, | ||
2213 | 0x01a19040, 0x01011012, 0x01016011, 0x40000100, | ||
2214 | 0x40000100, 0x40000100, 0x40000100, 0x01442070, | ||
2215 | 0x40000100, 0x40000100 | ||
2216 | }; | ||
2217 | |||
2157 | static unsigned int dell_3st_pin_configs[14] = { | 2218 | static unsigned int dell_3st_pin_configs[14] = { |
2158 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, | 2219 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, |
2159 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, | 2220 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, |
@@ -2166,6 +2227,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | |||
2166 | [STAC_D965_REF] = ref927x_pin_configs, | 2227 | [STAC_D965_REF] = ref927x_pin_configs, |
2167 | [STAC_D965_3ST] = d965_3st_pin_configs, | 2228 | [STAC_D965_3ST] = d965_3st_pin_configs, |
2168 | [STAC_D965_5ST] = d965_5st_pin_configs, | 2229 | [STAC_D965_5ST] = d965_5st_pin_configs, |
2230 | [STAC_D965_5ST_NO_FP] = d965_5st_no_fp_pin_configs, | ||
2169 | [STAC_DELL_3ST] = dell_3st_pin_configs, | 2231 | [STAC_DELL_3ST] = dell_3st_pin_configs, |
2170 | [STAC_DELL_BIOS] = NULL, | 2232 | [STAC_DELL_BIOS] = NULL, |
2171 | }; | 2233 | }; |
@@ -2176,6 +2238,7 @@ static const char *stac927x_models[STAC_927X_MODELS] = { | |||
2176 | [STAC_D965_REF] = "ref", | 2238 | [STAC_D965_REF] = "ref", |
2177 | [STAC_D965_3ST] = "3stack", | 2239 | [STAC_D965_3ST] = "3stack", |
2178 | [STAC_D965_5ST] = "5stack", | 2240 | [STAC_D965_5ST] = "5stack", |
2241 | [STAC_D965_5ST_NO_FP] = "5stack-no-fp", | ||
2179 | [STAC_DELL_3ST] = "dell-3stack", | 2242 | [STAC_DELL_3ST] = "dell-3stack", |
2180 | [STAC_DELL_BIOS] = "dell-bios", | 2243 | [STAC_DELL_BIOS] = "dell-bios", |
2181 | }; | 2244 | }; |
@@ -2535,7 +2598,8 @@ static int stac92xx_build_pcms(struct hda_codec *codec) | |||
2535 | return 0; | 2598 | return 0; |
2536 | } | 2599 | } |
2537 | 2600 | ||
2538 | static unsigned int stac92xx_get_vref(struct hda_codec *codec, hda_nid_t nid) | 2601 | static unsigned int stac92xx_get_default_vref(struct hda_codec *codec, |
2602 | hda_nid_t nid) | ||
2539 | { | 2603 | { |
2540 | unsigned int pincap = snd_hda_query_pin_caps(codec, nid); | 2604 | unsigned int pincap = snd_hda_query_pin_caps(codec, nid); |
2541 | pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; | 2605 | pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; |
@@ -2589,15 +2653,108 @@ static int stac92xx_hp_switch_put(struct snd_kcontrol *kcontrol, | |||
2589 | return 1; | 2653 | return 1; |
2590 | } | 2654 | } |
2591 | 2655 | ||
2592 | #define stac92xx_io_switch_info snd_ctl_boolean_mono_info | 2656 | static int stac92xx_dc_bias_info(struct snd_kcontrol *kcontrol, |
2657 | struct snd_ctl_elem_info *uinfo) | ||
2658 | { | ||
2659 | int i; | ||
2660 | static char *texts[] = { | ||
2661 | "Mic In", "Line In", "Line Out" | ||
2662 | }; | ||
2663 | |||
2664 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2665 | struct sigmatel_spec *spec = codec->spec; | ||
2666 | hda_nid_t nid = kcontrol->private_value; | ||
2667 | |||
2668 | if (nid == spec->mic_switch || nid == spec->line_switch) | ||
2669 | i = 3; | ||
2670 | else | ||
2671 | i = 2; | ||
2672 | |||
2673 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2674 | uinfo->value.enumerated.items = i; | ||
2675 | uinfo->count = 1; | ||
2676 | if (uinfo->value.enumerated.item >= i) | ||
2677 | uinfo->value.enumerated.item = i-1; | ||
2678 | strcpy(uinfo->value.enumerated.name, | ||
2679 | texts[uinfo->value.enumerated.item]); | ||
2680 | |||
2681 | return 0; | ||
2682 | } | ||
2683 | |||
2684 | static int stac92xx_dc_bias_get(struct snd_kcontrol *kcontrol, | ||
2685 | struct snd_ctl_elem_value *ucontrol) | ||
2686 | { | ||
2687 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2688 | hda_nid_t nid = kcontrol->private_value; | ||
2689 | unsigned int vref = stac92xx_vref_get(codec, nid); | ||
2690 | |||
2691 | if (vref == stac92xx_get_default_vref(codec, nid)) | ||
2692 | ucontrol->value.enumerated.item[0] = 0; | ||
2693 | else if (vref == AC_PINCTL_VREF_GRD) | ||
2694 | ucontrol->value.enumerated.item[0] = 1; | ||
2695 | else if (vref == AC_PINCTL_VREF_HIZ) | ||
2696 | ucontrol->value.enumerated.item[0] = 2; | ||
2697 | |||
2698 | return 0; | ||
2699 | } | ||
2700 | |||
2701 | static int stac92xx_dc_bias_put(struct snd_kcontrol *kcontrol, | ||
2702 | struct snd_ctl_elem_value *ucontrol) | ||
2703 | { | ||
2704 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2705 | unsigned int new_vref = 0; | ||
2706 | unsigned int error; | ||
2707 | hda_nid_t nid = kcontrol->private_value; | ||
2708 | |||
2709 | if (ucontrol->value.enumerated.item[0] == 0) | ||
2710 | new_vref = stac92xx_get_default_vref(codec, nid); | ||
2711 | else if (ucontrol->value.enumerated.item[0] == 1) | ||
2712 | new_vref = AC_PINCTL_VREF_GRD; | ||
2713 | else if (ucontrol->value.enumerated.item[0] == 2) | ||
2714 | new_vref = AC_PINCTL_VREF_HIZ; | ||
2715 | else | ||
2716 | return 0; | ||
2717 | |||
2718 | if (new_vref != stac92xx_vref_get(codec, nid)) { | ||
2719 | error = stac92xx_vref_set(codec, nid, new_vref); | ||
2720 | return error; | ||
2721 | } | ||
2722 | |||
2723 | return 0; | ||
2724 | } | ||
2725 | |||
2726 | static int stac92xx_io_switch_info(struct snd_kcontrol *kcontrol, | ||
2727 | struct snd_ctl_elem_info *uinfo) | ||
2728 | { | ||
2729 | static char *texts[2]; | ||
2730 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
2731 | struct sigmatel_spec *spec = codec->spec; | ||
2732 | |||
2733 | if (kcontrol->private_value == spec->line_switch) | ||
2734 | texts[0] = "Line In"; | ||
2735 | else | ||
2736 | texts[0] = "Mic In"; | ||
2737 | texts[1] = "Line Out"; | ||
2738 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
2739 | uinfo->value.enumerated.items = 2; | ||
2740 | uinfo->count = 1; | ||
2741 | |||
2742 | if (uinfo->value.enumerated.item >= 2) | ||
2743 | uinfo->value.enumerated.item = 1; | ||
2744 | strcpy(uinfo->value.enumerated.name, | ||
2745 | texts[uinfo->value.enumerated.item]); | ||
2746 | |||
2747 | return 0; | ||
2748 | } | ||
2593 | 2749 | ||
2594 | static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 2750 | static int stac92xx_io_switch_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
2595 | { | 2751 | { |
2596 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2752 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2597 | struct sigmatel_spec *spec = codec->spec; | 2753 | struct sigmatel_spec *spec = codec->spec; |
2598 | int io_idx = kcontrol-> private_value & 0xff; | 2754 | hda_nid_t nid = kcontrol->private_value; |
2755 | int io_idx = (nid == spec->mic_switch) ? 1 : 0; | ||
2599 | 2756 | ||
2600 | ucontrol->value.integer.value[0] = spec->io_switch[io_idx]; | 2757 | ucontrol->value.enumerated.item[0] = spec->io_switch[io_idx]; |
2601 | return 0; | 2758 | return 0; |
2602 | } | 2759 | } |
2603 | 2760 | ||
@@ -2605,9 +2762,9 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
2605 | { | 2762 | { |
2606 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | 2763 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); |
2607 | struct sigmatel_spec *spec = codec->spec; | 2764 | struct sigmatel_spec *spec = codec->spec; |
2608 | hda_nid_t nid = kcontrol->private_value >> 8; | 2765 | hda_nid_t nid = kcontrol->private_value; |
2609 | int io_idx = kcontrol-> private_value & 0xff; | 2766 | int io_idx = (nid == spec->mic_switch) ? 1 : 0; |
2610 | unsigned short val = !!ucontrol->value.integer.value[0]; | 2767 | unsigned short val = !!ucontrol->value.enumerated.item[0]; |
2611 | 2768 | ||
2612 | spec->io_switch[io_idx] = val; | 2769 | spec->io_switch[io_idx] = val; |
2613 | 2770 | ||
@@ -2616,7 +2773,7 @@ static int stac92xx_io_switch_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
2616 | else { | 2773 | else { |
2617 | unsigned int pinctl = AC_PINCTL_IN_EN; | 2774 | unsigned int pinctl = AC_PINCTL_IN_EN; |
2618 | if (io_idx) /* set VREF for mic */ | 2775 | if (io_idx) /* set VREF for mic */ |
2619 | pinctl |= stac92xx_get_vref(codec, nid); | 2776 | pinctl |= stac92xx_get_default_vref(codec, nid); |
2620 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 2777 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
2621 | } | 2778 | } |
2622 | 2779 | ||
@@ -2697,7 +2854,8 @@ enum { | |||
2697 | STAC_CTL_WIDGET_AMP_VOL, | 2854 | STAC_CTL_WIDGET_AMP_VOL, |
2698 | STAC_CTL_WIDGET_HP_SWITCH, | 2855 | STAC_CTL_WIDGET_HP_SWITCH, |
2699 | STAC_CTL_WIDGET_IO_SWITCH, | 2856 | STAC_CTL_WIDGET_IO_SWITCH, |
2700 | STAC_CTL_WIDGET_CLFE_SWITCH | 2857 | STAC_CTL_WIDGET_CLFE_SWITCH, |
2858 | STAC_CTL_WIDGET_DC_BIAS | ||
2701 | }; | 2859 | }; |
2702 | 2860 | ||
2703 | static struct snd_kcontrol_new stac92xx_control_templates[] = { | 2861 | static struct snd_kcontrol_new stac92xx_control_templates[] = { |
@@ -2709,6 +2867,7 @@ static struct snd_kcontrol_new stac92xx_control_templates[] = { | |||
2709 | STAC_CODEC_HP_SWITCH(NULL), | 2867 | STAC_CODEC_HP_SWITCH(NULL), |
2710 | STAC_CODEC_IO_SWITCH(NULL, 0), | 2868 | STAC_CODEC_IO_SWITCH(NULL, 0), |
2711 | STAC_CODEC_CLFE_SWITCH(NULL, 0), | 2869 | STAC_CODEC_CLFE_SWITCH(NULL, 0), |
2870 | DC_BIAS(NULL, 0, 0), | ||
2712 | }; | 2871 | }; |
2713 | 2872 | ||
2714 | /* add dynamic controls */ | 2873 | /* add dynamic controls */ |
@@ -2772,6 +2931,34 @@ static struct snd_kcontrol_new stac_input_src_temp = { | |||
2772 | .put = stac92xx_mux_enum_put, | 2931 | .put = stac92xx_mux_enum_put, |
2773 | }; | 2932 | }; |
2774 | 2933 | ||
2934 | static inline int stac92xx_add_jack_mode_control(struct hda_codec *codec, | ||
2935 | hda_nid_t nid, int idx) | ||
2936 | { | ||
2937 | int def_conf = snd_hda_codec_get_pincfg(codec, nid); | ||
2938 | int control = 0; | ||
2939 | struct sigmatel_spec *spec = codec->spec; | ||
2940 | char name[22]; | ||
2941 | |||
2942 | if (!((get_defcfg_connect(def_conf)) & AC_JACK_PORT_FIXED)) { | ||
2943 | if (stac92xx_get_default_vref(codec, nid) == AC_PINCTL_VREF_GRD | ||
2944 | && nid == spec->line_switch) | ||
2945 | control = STAC_CTL_WIDGET_IO_SWITCH; | ||
2946 | else if (snd_hda_query_pin_caps(codec, nid) | ||
2947 | & (AC_PINCAP_VREF_GRD << AC_PINCAP_VREF_SHIFT)) | ||
2948 | control = STAC_CTL_WIDGET_DC_BIAS; | ||
2949 | else if (nid == spec->mic_switch) | ||
2950 | control = STAC_CTL_WIDGET_IO_SWITCH; | ||
2951 | } | ||
2952 | |||
2953 | if (control) { | ||
2954 | strcpy(name, auto_pin_cfg_labels[idx]); | ||
2955 | return stac92xx_add_control(codec->spec, control, | ||
2956 | strcat(name, " Jack Mode"), nid); | ||
2957 | } | ||
2958 | |||
2959 | return 0; | ||
2960 | } | ||
2961 | |||
2775 | static int stac92xx_add_input_source(struct sigmatel_spec *spec) | 2962 | static int stac92xx_add_input_source(struct sigmatel_spec *spec) |
2776 | { | 2963 | { |
2777 | struct snd_kcontrol_new *knew; | 2964 | struct snd_kcontrol_new *knew; |
@@ -3134,7 +3321,9 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |||
3134 | const struct auto_pin_cfg *cfg) | 3321 | const struct auto_pin_cfg *cfg) |
3135 | { | 3322 | { |
3136 | struct sigmatel_spec *spec = codec->spec; | 3323 | struct sigmatel_spec *spec = codec->spec; |
3324 | hda_nid_t nid; | ||
3137 | int err; | 3325 | int err; |
3326 | int idx; | ||
3138 | 3327 | ||
3139 | err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, | 3328 | err = create_multi_out_ctls(codec, cfg->line_outs, cfg->line_out_pins, |
3140 | spec->multiout.dac_nids, | 3329 | spec->multiout.dac_nids, |
@@ -3151,20 +3340,13 @@ static int stac92xx_auto_create_multi_out_ctls(struct hda_codec *codec, | |||
3151 | return err; | 3340 | return err; |
3152 | } | 3341 | } |
3153 | 3342 | ||
3154 | if (spec->line_switch) { | 3343 | for (idx = AUTO_PIN_MIC; idx <= AUTO_PIN_FRONT_LINE; idx++) { |
3155 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, | 3344 | nid = cfg->input_pins[idx]; |
3156 | "Line In as Output Switch", | 3345 | if (nid) { |
3157 | spec->line_switch << 8); | 3346 | err = stac92xx_add_jack_mode_control(codec, nid, idx); |
3158 | if (err < 0) | 3347 | if (err < 0) |
3159 | return err; | 3348 | return err; |
3160 | } | 3349 | } |
3161 | |||
3162 | if (spec->mic_switch) { | ||
3163 | err = stac92xx_add_control(spec, STAC_CTL_WIDGET_IO_SWITCH, | ||
3164 | "Mic as Output Switch", | ||
3165 | (spec->mic_switch << 8) | 1); | ||
3166 | if (err < 0) | ||
3167 | return err; | ||
3168 | } | 3350 | } |
3169 | 3351 | ||
3170 | return 0; | 3352 | return 0; |
@@ -3629,6 +3811,8 @@ static int stac92xx_parse_auto_config(struct hda_codec *codec, hda_nid_t dig_out | |||
3629 | err = snd_hda_attach_beep_device(codec, nid); | 3811 | err = snd_hda_attach_beep_device(codec, nid); |
3630 | if (err < 0) | 3812 | if (err < 0) |
3631 | return err; | 3813 | return err; |
3814 | /* IDT/STAC codecs have linear beep tone parameter */ | ||
3815 | codec->beep->linear_tone = 1; | ||
3632 | /* if no beep switch is available, make its own one */ | 3816 | /* if no beep switch is available, make its own one */ |
3633 | caps = query_amp_caps(codec, nid, HDA_OUTPUT); | 3817 | caps = query_amp_caps(codec, nid, HDA_OUTPUT); |
3634 | if (codec->beep && | 3818 | if (codec->beep && |
@@ -4072,14 +4256,19 @@ static int stac92xx_init(struct hda_codec *codec) | |||
4072 | unsigned int pinctl, conf; | 4256 | unsigned int pinctl, conf; |
4073 | if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { | 4257 | if (i == AUTO_PIN_MIC || i == AUTO_PIN_FRONT_MIC) { |
4074 | /* for mic pins, force to initialize */ | 4258 | /* for mic pins, force to initialize */ |
4075 | pinctl = stac92xx_get_vref(codec, nid); | 4259 | pinctl = stac92xx_get_default_vref(codec, nid); |
4076 | pinctl |= AC_PINCTL_IN_EN; | 4260 | pinctl |= AC_PINCTL_IN_EN; |
4077 | stac92xx_auto_set_pinctl(codec, nid, pinctl); | 4261 | stac92xx_auto_set_pinctl(codec, nid, pinctl); |
4078 | } else { | 4262 | } else { |
4079 | pinctl = snd_hda_codec_read(codec, nid, 0, | 4263 | pinctl = snd_hda_codec_read(codec, nid, 0, |
4080 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 4264 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |
4081 | /* if PINCTL already set then skip */ | 4265 | /* if PINCTL already set then skip */ |
4082 | if (!(pinctl & AC_PINCTL_IN_EN)) { | 4266 | /* Also, if both INPUT and OUTPUT are set, |
4267 | * it must be a BIOS bug; need to override, too | ||
4268 | */ | ||
4269 | if (!(pinctl & AC_PINCTL_IN_EN) || | ||
4270 | (pinctl & AC_PINCTL_OUT_EN)) { | ||
4271 | pinctl &= ~AC_PINCTL_OUT_EN; | ||
4083 | pinctl |= AC_PINCTL_IN_EN; | 4272 | pinctl |= AC_PINCTL_IN_EN; |
4084 | stac92xx_auto_set_pinctl(codec, nid, | 4273 | stac92xx_auto_set_pinctl(codec, nid, |
4085 | pinctl); | 4274 | pinctl); |
@@ -4520,17 +4709,19 @@ static int stac92xx_resume(struct hda_codec *codec) | |||
4520 | return 0; | 4709 | return 0; |
4521 | } | 4710 | } |
4522 | 4711 | ||
4523 | |||
4524 | /* | 4712 | /* |
4525 | * using power check for controlling mute led of HP HDX notebooks | 4713 | * using power check for controlling mute led of HP notebooks |
4526 | * check for mute state only on Speakers (nid = 0x10) | 4714 | * check for mute state only on Speakers (nid = 0x10) |
4527 | * | 4715 | * |
4528 | * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise | 4716 | * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise |
4529 | * the LED is NOT working properly ! | 4717 | * the LED is NOT working properly ! |
4718 | * | ||
4719 | * Changed name to reflect that it now works for any designated | ||
4720 | * model, not just HP HDX. | ||
4530 | */ | 4721 | */ |
4531 | 4722 | ||
4532 | #ifdef CONFIG_SND_HDA_POWER_SAVE | 4723 | #ifdef CONFIG_SND_HDA_POWER_SAVE |
4533 | static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec, | 4724 | static int stac92xx_hp_check_power_status(struct hda_codec *codec, |
4534 | hda_nid_t nid) | 4725 | hda_nid_t nid) |
4535 | { | 4726 | { |
4536 | struct sigmatel_spec *spec = codec->spec; | 4727 | struct sigmatel_spec *spec = codec->spec; |
@@ -4538,9 +4729,9 @@ static int stac92xx_hp_hdx_check_power_status(struct hda_codec *codec, | |||
4538 | if (nid == 0x10) { | 4729 | if (nid == 0x10) { |
4539 | if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & | 4730 | if (snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & |
4540 | HDA_AMP_MUTE) | 4731 | HDA_AMP_MUTE) |
4541 | spec->gpio_data &= ~0x08; /* orange */ | 4732 | spec->gpio_data &= ~spec->gpio_led; /* orange */ |
4542 | else | 4733 | else |
4543 | spec->gpio_data |= 0x08; /* white */ | 4734 | spec->gpio_data |= spec->gpio_led; /* white */ |
4544 | 4735 | ||
4545 | stac_gpio_set(codec, spec->gpio_mask, | 4736 | stac_gpio_set(codec, spec->gpio_mask, |
4546 | spec->gpio_dir, | 4737 | spec->gpio_dir, |
@@ -5186,6 +5377,15 @@ again: | |||
5186 | if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) | 5377 | if (get_wcaps(codec, 0xa) & AC_WCAP_IN_AMP) |
5187 | snd_hda_sequence_write_cache(codec, unmute_init); | 5378 | snd_hda_sequence_write_cache(codec, unmute_init); |
5188 | 5379 | ||
5380 | /* Some HP machines seem to have unstable codec communications | ||
5381 | * especially with ATI fglrx driver. For recovering from the | ||
5382 | * CORB/RIRB stall, allow the BUS reset and keep always sync | ||
5383 | */ | ||
5384 | if (spec->board_config == STAC_HP_DV5) { | ||
5385 | codec->bus->sync_write = 1; | ||
5386 | codec->bus->allow_bus_reset = 1; | ||
5387 | } | ||
5388 | |||
5189 | spec->aloopback_ctl = stac92hd71bxx_loopback; | 5389 | spec->aloopback_ctl = stac92hd71bxx_loopback; |
5190 | spec->aloopback_mask = 0x50; | 5390 | spec->aloopback_mask = 0x50; |
5191 | spec->aloopback_shift = 0; | 5391 | spec->aloopback_shift = 0; |
@@ -5219,6 +5419,15 @@ again: | |||
5219 | spec->num_smuxes = 0; | 5419 | spec->num_smuxes = 0; |
5220 | spec->num_dmuxes = 1; | 5420 | spec->num_dmuxes = 1; |
5221 | break; | 5421 | break; |
5422 | case STAC_HP_DV4_1222NR: | ||
5423 | spec->num_dmics = 1; | ||
5424 | /* I don't know if it needs 1 or 2 smuxes - will wait for | ||
5425 | * bug reports to fix if needed | ||
5426 | */ | ||
5427 | spec->num_smuxes = 1; | ||
5428 | spec->num_dmuxes = 1; | ||
5429 | spec->gpio_led = 0x01; | ||
5430 | /* fallthrough */ | ||
5222 | case STAC_HP_DV5: | 5431 | case STAC_HP_DV5: |
5223 | snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); | 5432 | snd_hda_codec_set_pincfg(codec, 0x0d, 0x90170010); |
5224 | stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); | 5433 | stac92xx_auto_set_pinctl(codec, 0x0d, AC_PINCTL_OUT_EN); |
@@ -5227,22 +5436,21 @@ again: | |||
5227 | spec->num_dmics = 1; | 5436 | spec->num_dmics = 1; |
5228 | spec->num_dmuxes = 1; | 5437 | spec->num_dmuxes = 1; |
5229 | spec->num_smuxes = 1; | 5438 | spec->num_smuxes = 1; |
5230 | /* | ||
5231 | * For controlling MUTE LED on HP HDX16/HDX18 notebooks, | ||
5232 | * the CONFIG_SND_HDA_POWER_SAVE is needed to be set. | ||
5233 | */ | ||
5234 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
5235 | /* orange/white mute led on GPIO3, orange=0, white=1 */ | 5439 | /* orange/white mute led on GPIO3, orange=0, white=1 */ |
5236 | spec->gpio_mask |= 0x08; | 5440 | spec->gpio_led = 0x08; |
5237 | spec->gpio_dir |= 0x08; | 5441 | break; |
5238 | spec->gpio_data |= 0x08; /* set to white */ | 5442 | } |
5239 | 5443 | ||
5444 | #ifdef CONFIG_SND_HDA_POWER_SAVE | ||
5445 | if (spec->gpio_led) { | ||
5446 | spec->gpio_mask |= spec->gpio_led; | ||
5447 | spec->gpio_dir |= spec->gpio_led; | ||
5448 | spec->gpio_data |= spec->gpio_led; | ||
5240 | /* register check_power_status callback. */ | 5449 | /* register check_power_status callback. */ |
5241 | codec->patch_ops.check_power_status = | 5450 | codec->patch_ops.check_power_status = |
5242 | stac92xx_hp_hdx_check_power_status; | 5451 | stac92xx_hp_check_power_status; |
5452 | } | ||
5243 | #endif | 5453 | #endif |
5244 | break; | ||
5245 | }; | ||
5246 | 5454 | ||
5247 | spec->multiout.dac_nids = spec->dac_nids; | 5455 | spec->multiout.dac_nids = spec->dac_nids; |
5248 | if (spec->dinput_mux) | 5456 | if (spec->dinput_mux) |
@@ -5267,7 +5475,7 @@ again: | |||
5267 | codec->proc_widget_hook = stac92hd7x_proc_hook; | 5475 | codec->proc_widget_hook = stac92hd7x_proc_hook; |
5268 | 5476 | ||
5269 | return 0; | 5477 | return 0; |
5270 | }; | 5478 | } |
5271 | 5479 | ||
5272 | static int patch_stac922x(struct hda_codec *codec) | 5480 | static int patch_stac922x(struct hda_codec *codec) |
5273 | { | 5481 | { |
@@ -5422,7 +5630,7 @@ static int patch_stac927x(struct hda_codec *codec) | |||
5422 | /* correct the device field to SPDIF out */ | 5630 | /* correct the device field to SPDIF out */ |
5423 | snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070); | 5631 | snd_hda_codec_set_pincfg(codec, 0x21, 0x01442070); |
5424 | break; | 5632 | break; |
5425 | }; | 5633 | } |
5426 | /* configure the analog microphone on some laptops */ | 5634 | /* configure the analog microphone on some laptops */ |
5427 | snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130); | 5635 | snd_hda_codec_set_pincfg(codec, 0x0c, 0x90a79130); |
5428 | /* correct the front output jack as a hp out */ | 5636 | /* correct the front output jack as a hp out */ |
@@ -5732,6 +5940,7 @@ static struct hda_codec_preset snd_hda_preset_sigmatel[] = { | |||
5732 | { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, | 5940 | { .id = 0x83847661, .name = "CXD9872RD/K", .patch = patch_stac9872 }, |
5733 | { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, | 5941 | { .id = 0x83847662, .name = "STAC9872AK", .patch = patch_stac9872 }, |
5734 | { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, | 5942 | { .id = 0x83847664, .name = "CXD9872AKD", .patch = patch_stac9872 }, |
5943 | { .id = 0x83847698, .name = "STAC9205", .patch = patch_stac9205 }, | ||
5735 | { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, | 5944 | { .id = 0x838476a0, .name = "STAC9205", .patch = patch_stac9205 }, |
5736 | { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, | 5945 | { .id = 0x838476a1, .name = "STAC9205D", .patch = patch_stac9205 }, |
5737 | { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, | 5946 | { .id = 0x838476a2, .name = "STAC9204", .patch = patch_stac9205 }, |
diff --git a/sound/pci/hda/patch_via.c b/sound/pci/hda/patch_via.c index b25a5cc637d6..8e004fb6961a 100644 --- a/sound/pci/hda/patch_via.c +++ b/sound/pci/hda/patch_via.c | |||
@@ -205,7 +205,7 @@ struct via_spec { | |||
205 | 205 | ||
206 | /* playback */ | 206 | /* playback */ |
207 | struct hda_multi_out multiout; | 207 | struct hda_multi_out multiout; |
208 | hda_nid_t extra_dig_out_nid; | 208 | hda_nid_t slave_dig_outs[2]; |
209 | 209 | ||
210 | /* capture */ | 210 | /* capture */ |
211 | unsigned int num_adc_nids; | 211 | unsigned int num_adc_nids; |
@@ -731,21 +731,6 @@ static int via_dig_playback_pcm_close(struct hda_pcm_stream *hinfo, | |||
731 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); | 731 | return snd_hda_multi_out_dig_close(codec, &spec->multiout); |
732 | } | 732 | } |
733 | 733 | ||
734 | /* setup SPDIF output stream */ | ||
735 | static void setup_dig_playback_stream(struct hda_codec *codec, hda_nid_t nid, | ||
736 | unsigned int stream_tag, unsigned int format) | ||
737 | { | ||
738 | /* turn off SPDIF once; otherwise the IEC958 bits won't be updated */ | ||
739 | if (codec->spdif_ctls & AC_DIG1_ENABLE) | ||
740 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | ||
741 | codec->spdif_ctls & ~AC_DIG1_ENABLE & 0xff); | ||
742 | snd_hda_codec_setup_stream(codec, nid, stream_tag, 0, format); | ||
743 | /* turn on again (if needed) */ | ||
744 | if (codec->spdif_ctls & AC_DIG1_ENABLE) | ||
745 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_DIGI_CONVERT_1, | ||
746 | codec->spdif_ctls & 0xff); | ||
747 | } | ||
748 | |||
749 | static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 734 | static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, |
750 | struct hda_codec *codec, | 735 | struct hda_codec *codec, |
751 | unsigned int stream_tag, | 736 | unsigned int stream_tag, |
@@ -753,19 +738,16 @@ static int via_dig_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | |||
753 | struct snd_pcm_substream *substream) | 738 | struct snd_pcm_substream *substream) |
754 | { | 739 | { |
755 | struct via_spec *spec = codec->spec; | 740 | struct via_spec *spec = codec->spec; |
756 | hda_nid_t nid; | 741 | return snd_hda_multi_out_dig_prepare(codec, &spec->multiout, |
757 | 742 | stream_tag, format, substream); | |
758 | /* 1st or 2nd S/PDIF */ | 743 | } |
759 | if (substream->number == 0) | ||
760 | nid = spec->multiout.dig_out_nid; | ||
761 | else if (substream->number == 1) | ||
762 | nid = spec->extra_dig_out_nid; | ||
763 | else | ||
764 | return -1; | ||
765 | 744 | ||
766 | mutex_lock(&codec->spdif_mutex); | 745 | static int via_dig_playback_pcm_cleanup(struct hda_pcm_stream *hinfo, |
767 | setup_dig_playback_stream(codec, nid, stream_tag, format); | 746 | struct hda_codec *codec, |
768 | mutex_unlock(&codec->spdif_mutex); | 747 | struct snd_pcm_substream *substream) |
748 | { | ||
749 | struct via_spec *spec = codec->spec; | ||
750 | snd_hda_multi_out_dig_cleanup(codec, &spec->multiout); | ||
769 | return 0; | 751 | return 0; |
770 | } | 752 | } |
771 | 753 | ||
@@ -842,7 +824,8 @@ static struct hda_pcm_stream vt1708_pcm_digital_playback = { | |||
842 | .ops = { | 824 | .ops = { |
843 | .open = via_dig_playback_pcm_open, | 825 | .open = via_dig_playback_pcm_open, |
844 | .close = via_dig_playback_pcm_close, | 826 | .close = via_dig_playback_pcm_close, |
845 | .prepare = via_dig_playback_pcm_prepare | 827 | .prepare = via_dig_playback_pcm_prepare, |
828 | .cleanup = via_dig_playback_pcm_cleanup | ||
846 | }, | 829 | }, |
847 | }; | 830 | }; |
848 | 831 | ||
@@ -874,13 +857,6 @@ static int via_build_controls(struct hda_codec *codec) | |||
874 | if (err < 0) | 857 | if (err < 0) |
875 | return err; | 858 | return err; |
876 | spec->multiout.share_spdif = 1; | 859 | spec->multiout.share_spdif = 1; |
877 | |||
878 | if (spec->extra_dig_out_nid) { | ||
879 | err = snd_hda_create_spdif_out_ctls(codec, | ||
880 | spec->extra_dig_out_nid); | ||
881 | if (err < 0) | ||
882 | return err; | ||
883 | } | ||
884 | } | 860 | } |
885 | if (spec->dig_in_nid) { | 861 | if (spec->dig_in_nid) { |
886 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); | 862 | err = snd_hda_create_spdif_in_ctls(codec, spec->dig_in_nid); |
@@ -1013,10 +989,6 @@ static void via_unsol_event(struct hda_codec *codec, | |||
1013 | via_gpio_control(codec); | 989 | via_gpio_control(codec); |
1014 | } | 990 | } |
1015 | 991 | ||
1016 | static hda_nid_t slave_dig_outs[] = { | ||
1017 | 0, | ||
1018 | }; | ||
1019 | |||
1020 | static int via_init(struct hda_codec *codec) | 992 | static int via_init(struct hda_codec *codec) |
1021 | { | 993 | { |
1022 | struct via_spec *spec = codec->spec; | 994 | struct via_spec *spec = codec->spec; |
@@ -1051,8 +1023,9 @@ static int via_init(struct hda_codec *codec) | |||
1051 | snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, | 1023 | snd_hda_codec_write(codec, spec->autocfg.dig_in_pin, 0, |
1052 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); | 1024 | AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_IN); |
1053 | 1025 | ||
1054 | /* no slave outs */ | 1026 | /* assign slave outs */ |
1055 | codec->slave_dig_outs = slave_dig_outs; | 1027 | if (spec->slave_dig_outs[0]) |
1028 | codec->slave_dig_outs = spec->slave_dig_outs; | ||
1056 | 1029 | ||
1057 | return 0; | 1030 | return 0; |
1058 | } | 1031 | } |
@@ -2134,7 +2107,8 @@ static struct hda_pcm_stream vt1708B_pcm_digital_playback = { | |||
2134 | .ops = { | 2107 | .ops = { |
2135 | .open = via_dig_playback_pcm_open, | 2108 | .open = via_dig_playback_pcm_open, |
2136 | .close = via_dig_playback_pcm_close, | 2109 | .close = via_dig_playback_pcm_close, |
2137 | .prepare = via_dig_playback_pcm_prepare | 2110 | .prepare = via_dig_playback_pcm_prepare, |
2111 | .cleanup = via_dig_playback_pcm_cleanup | ||
2138 | }, | 2112 | }, |
2139 | }; | 2113 | }; |
2140 | 2114 | ||
@@ -2589,14 +2563,15 @@ static struct hda_pcm_stream vt1708S_pcm_analog_capture = { | |||
2589 | }; | 2563 | }; |
2590 | 2564 | ||
2591 | static struct hda_pcm_stream vt1708S_pcm_digital_playback = { | 2565 | static struct hda_pcm_stream vt1708S_pcm_digital_playback = { |
2592 | .substreams = 2, | 2566 | .substreams = 1, |
2593 | .channels_min = 2, | 2567 | .channels_min = 2, |
2594 | .channels_max = 2, | 2568 | .channels_max = 2, |
2595 | /* NID is set in via_build_pcms */ | 2569 | /* NID is set in via_build_pcms */ |
2596 | .ops = { | 2570 | .ops = { |
2597 | .open = via_dig_playback_pcm_open, | 2571 | .open = via_dig_playback_pcm_open, |
2598 | .close = via_dig_playback_pcm_close, | 2572 | .close = via_dig_playback_pcm_close, |
2599 | .prepare = via_dig_playback_pcm_prepare | 2573 | .prepare = via_dig_playback_pcm_prepare, |
2574 | .cleanup = via_dig_playback_pcm_cleanup | ||
2600 | }, | 2575 | }, |
2601 | }; | 2576 | }; |
2602 | 2577 | ||
@@ -2805,14 +2780,37 @@ static int vt1708S_auto_create_analog_input_ctls(struct via_spec *spec, | |||
2805 | return 0; | 2780 | return 0; |
2806 | } | 2781 | } |
2807 | 2782 | ||
2783 | /* fill out digital output widgets; one for master and one for slave outputs */ | ||
2784 | static void fill_dig_outs(struct hda_codec *codec) | ||
2785 | { | ||
2786 | struct via_spec *spec = codec->spec; | ||
2787 | int i; | ||
2788 | |||
2789 | for (i = 0; i < spec->autocfg.dig_outs; i++) { | ||
2790 | hda_nid_t nid; | ||
2791 | int conn; | ||
2792 | |||
2793 | nid = spec->autocfg.dig_out_pins[i]; | ||
2794 | if (!nid) | ||
2795 | continue; | ||
2796 | conn = snd_hda_get_connections(codec, nid, &nid, 1); | ||
2797 | if (conn < 1) | ||
2798 | continue; | ||
2799 | if (!spec->multiout.dig_out_nid) | ||
2800 | spec->multiout.dig_out_nid = nid; | ||
2801 | else { | ||
2802 | spec->slave_dig_outs[0] = nid; | ||
2803 | break; /* at most two dig outs */ | ||
2804 | } | ||
2805 | } | ||
2806 | } | ||
2807 | |||
2808 | static int vt1708S_parse_auto_config(struct hda_codec *codec) | 2808 | static int vt1708S_parse_auto_config(struct hda_codec *codec) |
2809 | { | 2809 | { |
2810 | struct via_spec *spec = codec->spec; | 2810 | struct via_spec *spec = codec->spec; |
2811 | int err; | 2811 | int err; |
2812 | static hda_nid_t vt1708s_ignore[] = {0x21, 0}; | ||
2813 | 2812 | ||
2814 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | 2813 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); |
2815 | vt1708s_ignore); | ||
2816 | if (err < 0) | 2814 | if (err < 0) |
2817 | return err; | 2815 | return err; |
2818 | err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); | 2816 | err = vt1708S_auto_fill_dac_nids(spec, &spec->autocfg); |
@@ -2833,10 +2831,7 @@ static int vt1708S_parse_auto_config(struct hda_codec *codec) | |||
2833 | 2831 | ||
2834 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 2832 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
2835 | 2833 | ||
2836 | if (spec->autocfg.dig_outs) | 2834 | fill_dig_outs(codec); |
2837 | spec->multiout.dig_out_nid = VT1708S_DIGOUT_NID; | ||
2838 | |||
2839 | spec->extra_dig_out_nid = 0x15; | ||
2840 | 2835 | ||
2841 | if (spec->kctls.list) | 2836 | if (spec->kctls.list) |
2842 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | 2837 | spec->mixers[spec->num_mixers++] = spec->kctls.list; |
@@ -3000,7 +2995,8 @@ static struct hda_pcm_stream vt1702_pcm_digital_playback = { | |||
3000 | .ops = { | 2995 | .ops = { |
3001 | .open = via_dig_playback_pcm_open, | 2996 | .open = via_dig_playback_pcm_open, |
3002 | .close = via_dig_playback_pcm_close, | 2997 | .close = via_dig_playback_pcm_close, |
3003 | .prepare = via_dig_playback_pcm_prepare | 2998 | .prepare = via_dig_playback_pcm_prepare, |
2999 | .cleanup = via_dig_playback_pcm_cleanup | ||
3004 | }, | 3000 | }, |
3005 | }; | 3001 | }; |
3006 | 3002 | ||
@@ -3128,10 +3124,8 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) | |||
3128 | { | 3124 | { |
3129 | struct via_spec *spec = codec->spec; | 3125 | struct via_spec *spec = codec->spec; |
3130 | int err; | 3126 | int err; |
3131 | static hda_nid_t vt1702_ignore[] = {0x1C, 0}; | ||
3132 | 3127 | ||
3133 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, | 3128 | err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); |
3134 | vt1702_ignore); | ||
3135 | if (err < 0) | 3129 | if (err < 0) |
3136 | return err; | 3130 | return err; |
3137 | err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); | 3131 | err = vt1702_auto_fill_dac_nids(spec, &spec->autocfg); |
@@ -3152,10 +3146,7 @@ static int vt1702_parse_auto_config(struct hda_codec *codec) | |||
3152 | 3146 | ||
3153 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; | 3147 | spec->multiout.max_channels = spec->multiout.num_dacs * 2; |
3154 | 3148 | ||
3155 | if (spec->autocfg.dig_outs) | 3149 | fill_dig_outs(codec); |
3156 | spec->multiout.dig_out_nid = VT1702_DIGOUT_NID; | ||
3157 | |||
3158 | spec->extra_dig_out_nid = 0x1B; | ||
3159 | 3150 | ||
3160 | if (spec->kctls.list) | 3151 | if (spec->kctls.list) |
3161 | spec->mixers[spec->num_mixers++] = spec->kctls.list; | 3152 | spec->mixers[spec->num_mixers++] = spec->kctls.list; |
diff --git a/sound/pci/ice1712/Makefile b/sound/pci/ice1712/Makefile index f99fe089495d..536eae2ccf94 100644 --- a/sound/pci/ice1712/Makefile +++ b/sound/pci/ice1712/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o | 6 | snd-ice17xx-ak4xxx-objs := ak4xxx.o |
7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o | 7 | snd-ice1712-objs := ice1712.o delta.o hoontech.o ews.o |
8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o | 8 | snd-ice1724-objs := ice1724.o amp.o revo.o aureon.o vt1720_mobo.o pontis.o prodigy192.o prodigy_hifi.o juli.o phase.o wtm.o se.o maya44.o |
9 | 9 | ||
10 | # Toplevel Module Dependency | 10 | # Toplevel Module Dependency |
11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o | 11 | obj-$(CONFIG_SND_ICE1712) += snd-ice1712.o snd-ice17xx-ak4xxx.o |
diff --git a/sound/pci/ice1712/ice1712.h b/sound/pci/ice1712/ice1712.h index fdae6deba16b..adc909ec125c 100644 --- a/sound/pci/ice1712/ice1712.h +++ b/sound/pci/ice1712/ice1712.h | |||
@@ -335,6 +335,7 @@ struct snd_ice1712 { | |||
335 | unsigned int force_rdma1:1; /* VT1720/4 - RDMA1 as non-spdif */ | 335 | unsigned int force_rdma1:1; /* VT1720/4 - RDMA1 as non-spdif */ |
336 | unsigned int midi_output:1; /* VT1720/4: MIDI output triggered */ | 336 | unsigned int midi_output:1; /* VT1720/4: MIDI output triggered */ |
337 | unsigned int midi_input:1; /* VT1720/4: MIDI input triggered */ | 337 | unsigned int midi_input:1; /* VT1720/4: MIDI input triggered */ |
338 | unsigned int own_routing:1; /* VT1720/4: use own routing ctls */ | ||
338 | unsigned int num_total_dacs; /* total DACs */ | 339 | unsigned int num_total_dacs; /* total DACs */ |
339 | unsigned int num_total_adcs; /* total ADCs */ | 340 | unsigned int num_total_adcs; /* total ADCs */ |
340 | unsigned int cur_rate; /* current rate */ | 341 | unsigned int cur_rate; /* current rate */ |
@@ -458,10 +459,17 @@ static inline int snd_ice1712_gpio_read_bits(struct snd_ice1712 *ice, | |||
458 | return snd_ice1712_gpio_read(ice) & mask; | 459 | return snd_ice1712_gpio_read(ice) & mask; |
459 | } | 460 | } |
460 | 461 | ||
462 | /* route access functions */ | ||
463 | int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift); | ||
464 | int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val, | ||
465 | int shift); | ||
466 | |||
461 | int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice); | 467 | int snd_ice1712_spdif_build_controls(struct snd_ice1712 *ice); |
462 | 468 | ||
463 | int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, const struct snd_akm4xxx *template, | 469 | int snd_ice1712_akm4xxx_init(struct snd_akm4xxx *ak, |
464 | const struct snd_ak4xxx_private *priv, struct snd_ice1712 *ice); | 470 | const struct snd_akm4xxx *template, |
471 | const struct snd_ak4xxx_private *priv, | ||
472 | struct snd_ice1712 *ice); | ||
465 | void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice); | 473 | void snd_ice1712_akm4xxx_free(struct snd_ice1712 *ice); |
466 | int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice); | 474 | int snd_ice1712_akm4xxx_build_controls(struct snd_ice1712 *ice); |
467 | 475 | ||
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c index 128510e77a78..36ade77cf371 100644 --- a/sound/pci/ice1712/ice1724.c +++ b/sound/pci/ice1712/ice1724.c | |||
@@ -49,6 +49,7 @@ | |||
49 | #include "prodigy192.h" | 49 | #include "prodigy192.h" |
50 | #include "prodigy_hifi.h" | 50 | #include "prodigy_hifi.h" |
51 | #include "juli.h" | 51 | #include "juli.h" |
52 | #include "maya44.h" | ||
52 | #include "phase.h" | 53 | #include "phase.h" |
53 | #include "wtm.h" | 54 | #include "wtm.h" |
54 | #include "se.h" | 55 | #include "se.h" |
@@ -65,6 +66,7 @@ MODULE_SUPPORTED_DEVICE("{" | |||
65 | PRODIGY192_DEVICE_DESC | 66 | PRODIGY192_DEVICE_DESC |
66 | PRODIGY_HIFI_DEVICE_DESC | 67 | PRODIGY_HIFI_DEVICE_DESC |
67 | JULI_DEVICE_DESC | 68 | JULI_DEVICE_DESC |
69 | MAYA44_DEVICE_DESC | ||
68 | PHASE_DEVICE_DESC | 70 | PHASE_DEVICE_DESC |
69 | WTM_DEVICE_DESC | 71 | WTM_DEVICE_DESC |
70 | SE_DEVICE_DESC | 72 | SE_DEVICE_DESC |
@@ -626,7 +628,7 @@ static unsigned char stdclock_set_mclk(struct snd_ice1712 *ice, | |||
626 | return 0; | 628 | return 0; |
627 | } | 629 | } |
628 | 630 | ||
629 | static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, | 631 | static int snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, |
630 | int force) | 632 | int force) |
631 | { | 633 | { |
632 | unsigned long flags; | 634 | unsigned long flags; |
@@ -634,17 +636,18 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, | |||
634 | unsigned int i, old_rate; | 636 | unsigned int i, old_rate; |
635 | 637 | ||
636 | if (rate > ice->hw_rates->list[ice->hw_rates->count - 1]) | 638 | if (rate > ice->hw_rates->list[ice->hw_rates->count - 1]) |
637 | return; | 639 | return -EINVAL; |
640 | |||
638 | spin_lock_irqsave(&ice->reg_lock, flags); | 641 | spin_lock_irqsave(&ice->reg_lock, flags); |
639 | if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || | 642 | if ((inb(ICEMT1724(ice, DMA_CONTROL)) & DMA_STARTS) || |
640 | (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { | 643 | (inb(ICEMT1724(ice, DMA_PAUSE)) & DMA_PAUSES)) { |
641 | /* running? we cannot change the rate now... */ | 644 | /* running? we cannot change the rate now... */ |
642 | spin_unlock_irqrestore(&ice->reg_lock, flags); | 645 | spin_unlock_irqrestore(&ice->reg_lock, flags); |
643 | return; | 646 | return -EBUSY; |
644 | } | 647 | } |
645 | if (!force && is_pro_rate_locked(ice)) { | 648 | if (!force && is_pro_rate_locked(ice)) { |
646 | spin_unlock_irqrestore(&ice->reg_lock, flags); | 649 | spin_unlock_irqrestore(&ice->reg_lock, flags); |
647 | return; | 650 | return (rate == ice->cur_rate) ? 0 : -EBUSY; |
648 | } | 651 | } |
649 | 652 | ||
650 | old_rate = ice->get_rate(ice); | 653 | old_rate = ice->get_rate(ice); |
@@ -652,7 +655,7 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, | |||
652 | ice->set_rate(ice, rate); | 655 | ice->set_rate(ice, rate); |
653 | else if (rate == ice->cur_rate) { | 656 | else if (rate == ice->cur_rate) { |
654 | spin_unlock_irqrestore(&ice->reg_lock, flags); | 657 | spin_unlock_irqrestore(&ice->reg_lock, flags); |
655 | return; | 658 | return 0; |
656 | } | 659 | } |
657 | 660 | ||
658 | ice->cur_rate = rate; | 661 | ice->cur_rate = rate; |
@@ -674,13 +677,15 @@ static void snd_vt1724_set_pro_rate(struct snd_ice1712 *ice, unsigned int rate, | |||
674 | } | 677 | } |
675 | if (ice->spdif.ops.setup_rate) | 678 | if (ice->spdif.ops.setup_rate) |
676 | ice->spdif.ops.setup_rate(ice, rate); | 679 | ice->spdif.ops.setup_rate(ice, rate); |
680 | |||
681 | return 0; | ||
677 | } | 682 | } |
678 | 683 | ||
679 | static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, | 684 | static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, |
680 | struct snd_pcm_hw_params *hw_params) | 685 | struct snd_pcm_hw_params *hw_params) |
681 | { | 686 | { |
682 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); | 687 | struct snd_ice1712 *ice = snd_pcm_substream_chip(substream); |
683 | int i, chs; | 688 | int i, chs, err; |
684 | 689 | ||
685 | chs = params_channels(hw_params); | 690 | chs = params_channels(hw_params); |
686 | mutex_lock(&ice->open_mutex); | 691 | mutex_lock(&ice->open_mutex); |
@@ -715,7 +720,11 @@ static int snd_vt1724_pcm_hw_params(struct snd_pcm_substream *substream, | |||
715 | } | 720 | } |
716 | } | 721 | } |
717 | mutex_unlock(&ice->open_mutex); | 722 | mutex_unlock(&ice->open_mutex); |
718 | snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); | 723 | |
724 | err = snd_vt1724_set_pro_rate(ice, params_rate(hw_params), 0); | ||
725 | if (err < 0) | ||
726 | return err; | ||
727 | |||
719 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); | 728 | return snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params)); |
720 | } | 729 | } |
721 | 730 | ||
@@ -848,20 +857,39 @@ static snd_pcm_uframes_t snd_vt1724_pcm_pointer(struct snd_pcm_substream *substr | |||
848 | #endif | 857 | #endif |
849 | } | 858 | } |
850 | 859 | ||
851 | static const struct vt1724_pcm_reg vt1724_playback_pro_reg = { | 860 | static const struct vt1724_pcm_reg vt1724_pdma0_reg = { |
852 | .addr = VT1724_MT_PLAYBACK_ADDR, | 861 | .addr = VT1724_MT_PLAYBACK_ADDR, |
853 | .size = VT1724_MT_PLAYBACK_SIZE, | 862 | .size = VT1724_MT_PLAYBACK_SIZE, |
854 | .count = VT1724_MT_PLAYBACK_COUNT, | 863 | .count = VT1724_MT_PLAYBACK_COUNT, |
855 | .start = VT1724_PDMA0_START, | 864 | .start = VT1724_PDMA0_START, |
856 | }; | 865 | }; |
857 | 866 | ||
858 | static const struct vt1724_pcm_reg vt1724_capture_pro_reg = { | 867 | static const struct vt1724_pcm_reg vt1724_pdma4_reg = { |
868 | .addr = VT1724_MT_PDMA4_ADDR, | ||
869 | .size = VT1724_MT_PDMA4_SIZE, | ||
870 | .count = VT1724_MT_PDMA4_COUNT, | ||
871 | .start = VT1724_PDMA4_START, | ||
872 | }; | ||
873 | |||
874 | static const struct vt1724_pcm_reg vt1724_rdma0_reg = { | ||
859 | .addr = VT1724_MT_CAPTURE_ADDR, | 875 | .addr = VT1724_MT_CAPTURE_ADDR, |
860 | .size = VT1724_MT_CAPTURE_SIZE, | 876 | .size = VT1724_MT_CAPTURE_SIZE, |
861 | .count = VT1724_MT_CAPTURE_COUNT, | 877 | .count = VT1724_MT_CAPTURE_COUNT, |
862 | .start = VT1724_RDMA0_START, | 878 | .start = VT1724_RDMA0_START, |
863 | }; | 879 | }; |
864 | 880 | ||
881 | static const struct vt1724_pcm_reg vt1724_rdma1_reg = { | ||
882 | .addr = VT1724_MT_RDMA1_ADDR, | ||
883 | .size = VT1724_MT_RDMA1_SIZE, | ||
884 | .count = VT1724_MT_RDMA1_COUNT, | ||
885 | .start = VT1724_RDMA1_START, | ||
886 | }; | ||
887 | |||
888 | #define vt1724_playback_pro_reg vt1724_pdma0_reg | ||
889 | #define vt1724_playback_spdif_reg vt1724_pdma4_reg | ||
890 | #define vt1724_capture_pro_reg vt1724_rdma0_reg | ||
891 | #define vt1724_capture_spdif_reg vt1724_rdma1_reg | ||
892 | |||
865 | static const struct snd_pcm_hardware snd_vt1724_playback_pro = { | 893 | static const struct snd_pcm_hardware snd_vt1724_playback_pro = { |
866 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | | 894 | .info = (SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_INTERLEAVED | |
867 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | 895 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
@@ -1077,20 +1105,6 @@ static int __devinit snd_vt1724_pcm_profi(struct snd_ice1712 *ice, int device) | |||
1077 | * SPDIF PCM | 1105 | * SPDIF PCM |
1078 | */ | 1106 | */ |
1079 | 1107 | ||
1080 | static const struct vt1724_pcm_reg vt1724_playback_spdif_reg = { | ||
1081 | .addr = VT1724_MT_PDMA4_ADDR, | ||
1082 | .size = VT1724_MT_PDMA4_SIZE, | ||
1083 | .count = VT1724_MT_PDMA4_COUNT, | ||
1084 | .start = VT1724_PDMA4_START, | ||
1085 | }; | ||
1086 | |||
1087 | static const struct vt1724_pcm_reg vt1724_capture_spdif_reg = { | ||
1088 | .addr = VT1724_MT_RDMA1_ADDR, | ||
1089 | .size = VT1724_MT_RDMA1_SIZE, | ||
1090 | .count = VT1724_MT_RDMA1_COUNT, | ||
1091 | .start = VT1724_RDMA1_START, | ||
1092 | }; | ||
1093 | |||
1094 | /* update spdif control bits; call with reg_lock */ | 1108 | /* update spdif control bits; call with reg_lock */ |
1095 | static void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val) | 1109 | static void update_spdif_bits(struct snd_ice1712 *ice, unsigned int val) |
1096 | { | 1110 | { |
@@ -1963,7 +1977,7 @@ static inline int digital_route_shift(int idx) | |||
1963 | return idx * 3; | 1977 | return idx * 3; |
1964 | } | 1978 | } |
1965 | 1979 | ||
1966 | static int get_route_val(struct snd_ice1712 *ice, int shift) | 1980 | int snd_ice1724_get_route_val(struct snd_ice1712 *ice, int shift) |
1967 | { | 1981 | { |
1968 | unsigned long val; | 1982 | unsigned long val; |
1969 | unsigned char eitem; | 1983 | unsigned char eitem; |
@@ -1982,7 +1996,8 @@ static int get_route_val(struct snd_ice1712 *ice, int shift) | |||
1982 | return eitem; | 1996 | return eitem; |
1983 | } | 1997 | } |
1984 | 1998 | ||
1985 | static int put_route_val(struct snd_ice1712 *ice, unsigned int val, int shift) | 1999 | int snd_ice1724_put_route_val(struct snd_ice1712 *ice, unsigned int val, |
2000 | int shift) | ||
1986 | { | 2001 | { |
1987 | unsigned int old_val, nval; | 2002 | unsigned int old_val, nval; |
1988 | int change; | 2003 | int change; |
@@ -2010,7 +2025,7 @@ static int snd_vt1724_pro_route_analog_get(struct snd_kcontrol *kcontrol, | |||
2010 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 2025 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
2011 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 2026 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
2012 | ucontrol->value.enumerated.item[0] = | 2027 | ucontrol->value.enumerated.item[0] = |
2013 | get_route_val(ice, analog_route_shift(idx)); | 2028 | snd_ice1724_get_route_val(ice, analog_route_shift(idx)); |
2014 | return 0; | 2029 | return 0; |
2015 | } | 2030 | } |
2016 | 2031 | ||
@@ -2019,8 +2034,9 @@ static int snd_vt1724_pro_route_analog_put(struct snd_kcontrol *kcontrol, | |||
2019 | { | 2034 | { |
2020 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 2035 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
2021 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 2036 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
2022 | return put_route_val(ice, ucontrol->value.enumerated.item[0], | 2037 | return snd_ice1724_put_route_val(ice, |
2023 | analog_route_shift(idx)); | 2038 | ucontrol->value.enumerated.item[0], |
2039 | analog_route_shift(idx)); | ||
2024 | } | 2040 | } |
2025 | 2041 | ||
2026 | static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol, | 2042 | static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol, |
@@ -2029,7 +2045,7 @@ static int snd_vt1724_pro_route_spdif_get(struct snd_kcontrol *kcontrol, | |||
2029 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 2045 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
2030 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 2046 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
2031 | ucontrol->value.enumerated.item[0] = | 2047 | ucontrol->value.enumerated.item[0] = |
2032 | get_route_val(ice, digital_route_shift(idx)); | 2048 | snd_ice1724_get_route_val(ice, digital_route_shift(idx)); |
2033 | return 0; | 2049 | return 0; |
2034 | } | 2050 | } |
2035 | 2051 | ||
@@ -2038,11 +2054,13 @@ static int snd_vt1724_pro_route_spdif_put(struct snd_kcontrol *kcontrol, | |||
2038 | { | 2054 | { |
2039 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 2055 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
2040 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | 2056 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); |
2041 | return put_route_val(ice, ucontrol->value.enumerated.item[0], | 2057 | return snd_ice1724_put_route_val(ice, |
2042 | digital_route_shift(idx)); | 2058 | ucontrol->value.enumerated.item[0], |
2059 | digital_route_shift(idx)); | ||
2043 | } | 2060 | } |
2044 | 2061 | ||
2045 | static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = { | 2062 | static struct snd_kcontrol_new snd_vt1724_mixer_pro_analog_route __devinitdata = |
2063 | { | ||
2046 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 2064 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
2047 | .name = "H/W Playback Route", | 2065 | .name = "H/W Playback Route", |
2048 | .info = snd_vt1724_pro_route_info, | 2066 | .info = snd_vt1724_pro_route_info, |
@@ -2109,6 +2127,7 @@ static struct snd_ice1712_card_info *card_tables[] __devinitdata = { | |||
2109 | snd_vt1724_prodigy_hifi_cards, | 2127 | snd_vt1724_prodigy_hifi_cards, |
2110 | snd_vt1724_prodigy192_cards, | 2128 | snd_vt1724_prodigy192_cards, |
2111 | snd_vt1724_juli_cards, | 2129 | snd_vt1724_juli_cards, |
2130 | snd_vt1724_maya44_cards, | ||
2112 | snd_vt1724_phase_cards, | 2131 | snd_vt1724_phase_cards, |
2113 | snd_vt1724_wtm_cards, | 2132 | snd_vt1724_wtm_cards, |
2114 | snd_vt1724_se_cards, | 2133 | snd_vt1724_se_cards, |
@@ -2246,8 +2265,10 @@ static int __devinit snd_vt1724_read_eeprom(struct snd_ice1712 *ice, | |||
2246 | static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice) | 2265 | static void __devinit snd_vt1724_chip_reset(struct snd_ice1712 *ice) |
2247 | { | 2266 | { |
2248 | outb(VT1724_RESET , ICEREG1724(ice, CONTROL)); | 2267 | outb(VT1724_RESET , ICEREG1724(ice, CONTROL)); |
2268 | inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ | ||
2249 | msleep(10); | 2269 | msleep(10); |
2250 | outb(0, ICEREG1724(ice, CONTROL)); | 2270 | outb(0, ICEREG1724(ice, CONTROL)); |
2271 | inb(ICEREG1724(ice, CONTROL)); /* pci posting flush */ | ||
2251 | msleep(10); | 2272 | msleep(10); |
2252 | } | 2273 | } |
2253 | 2274 | ||
@@ -2277,9 +2298,12 @@ static int __devinit snd_vt1724_spdif_build_controls(struct snd_ice1712 *ice) | |||
2277 | if (snd_BUG_ON(!ice->pcm)) | 2298 | if (snd_BUG_ON(!ice->pcm)) |
2278 | return -EIO; | 2299 | return -EIO; |
2279 | 2300 | ||
2280 | err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice)); | 2301 | if (!ice->own_routing) { |
2281 | if (err < 0) | 2302 | err = snd_ctl_add(ice->card, |
2282 | return err; | 2303 | snd_ctl_new1(&snd_vt1724_mixer_pro_spdif_route, ice)); |
2304 | if (err < 0) | ||
2305 | return err; | ||
2306 | } | ||
2283 | 2307 | ||
2284 | err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice)); | 2308 | err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_spdif_switch, ice)); |
2285 | if (err < 0) | 2309 | if (err < 0) |
@@ -2326,7 +2350,7 @@ static int __devinit snd_vt1724_build_controls(struct snd_ice1712 *ice) | |||
2326 | if (err < 0) | 2350 | if (err < 0) |
2327 | return err; | 2351 | return err; |
2328 | 2352 | ||
2329 | if (ice->num_total_dacs > 0) { | 2353 | if (!ice->own_routing && ice->num_total_dacs > 0) { |
2330 | struct snd_kcontrol_new tmp = snd_vt1724_mixer_pro_analog_route; | 2354 | struct snd_kcontrol_new tmp = snd_vt1724_mixer_pro_analog_route; |
2331 | tmp.count = ice->num_total_dacs; | 2355 | tmp.count = ice->num_total_dacs; |
2332 | if (ice->vt1720 && tmp.count > 2) | 2356 | if (ice->vt1720 && tmp.count > 2) |
diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c new file mode 100644 index 000000000000..3e1c20ae2f1c --- /dev/null +++ b/sound/pci/ice1712/maya44.c | |||
@@ -0,0 +1,779 @@ | |||
1 | /* | ||
2 | * ALSA driver for ICEnsemble VT1724 (Envy24HT) | ||
3 | * | ||
4 | * Lowlevel functions for ESI Maya44 cards | ||
5 | * | ||
6 | * Copyright (c) 2009 Takashi Iwai <tiwai@suse.de> | ||
7 | * Based on the patches by Rainer Zimmermann <mail@lightshed.de> | ||
8 | * | ||
9 | * This program is free software; you can redistribute it and/or modify | ||
10 | * it under the terms of the GNU General Public License as published by | ||
11 | * the Free Software Foundation; either version 2 of the License, or | ||
12 | * (at your option) any later version. | ||
13 | * | ||
14 | * This program is distributed in the hope that it will be useful, | ||
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
17 | * GNU General Public License for more details. | ||
18 | * | ||
19 | * You should have received a copy of the GNU General Public License | ||
20 | * along with this program; if not, write to the Free Software | ||
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/init.h> | ||
26 | #include <linux/slab.h> | ||
27 | #include <linux/io.h> | ||
28 | #include <sound/core.h> | ||
29 | #include <sound/control.h> | ||
30 | #include <sound/pcm.h> | ||
31 | #include <sound/tlv.h> | ||
32 | |||
33 | #include "ice1712.h" | ||
34 | #include "envy24ht.h" | ||
35 | #include "maya44.h" | ||
36 | |||
37 | /* WM8776 register indexes */ | ||
38 | #define WM8776_REG_HEADPHONE_L 0x00 | ||
39 | #define WM8776_REG_HEADPHONE_R 0x01 | ||
40 | #define WM8776_REG_HEADPHONE_MASTER 0x02 | ||
41 | #define WM8776_REG_DAC_ATTEN_L 0x03 | ||
42 | #define WM8776_REG_DAC_ATTEN_R 0x04 | ||
43 | #define WM8776_REG_DAC_ATTEN_MASTER 0x05 | ||
44 | #define WM8776_REG_DAC_PHASE 0x06 | ||
45 | #define WM8776_REG_DAC_CONTROL 0x07 | ||
46 | #define WM8776_REG_DAC_MUTE 0x08 | ||
47 | #define WM8776_REG_DAC_DEEMPH 0x09 | ||
48 | #define WM8776_REG_DAC_IF_CONTROL 0x0a | ||
49 | #define WM8776_REG_ADC_IF_CONTROL 0x0b | ||
50 | #define WM8776_REG_MASTER_MODE_CONTROL 0x0c | ||
51 | #define WM8776_REG_POWERDOWN 0x0d | ||
52 | #define WM8776_REG_ADC_ATTEN_L 0x0e | ||
53 | #define WM8776_REG_ADC_ATTEN_R 0x0f | ||
54 | #define WM8776_REG_ADC_ALC1 0x10 | ||
55 | #define WM8776_REG_ADC_ALC2 0x11 | ||
56 | #define WM8776_REG_ADC_ALC3 0x12 | ||
57 | #define WM8776_REG_ADC_NOISE_GATE 0x13 | ||
58 | #define WM8776_REG_ADC_LIMITER 0x14 | ||
59 | #define WM8776_REG_ADC_MUX 0x15 | ||
60 | #define WM8776_REG_OUTPUT_MUX 0x16 | ||
61 | #define WM8776_REG_RESET 0x17 | ||
62 | |||
63 | #define WM8776_NUM_REGS 0x18 | ||
64 | |||
65 | /* clock ratio identifiers for snd_wm8776_set_rate() */ | ||
66 | #define WM8776_CLOCK_RATIO_128FS 0 | ||
67 | #define WM8776_CLOCK_RATIO_192FS 1 | ||
68 | #define WM8776_CLOCK_RATIO_256FS 2 | ||
69 | #define WM8776_CLOCK_RATIO_384FS 3 | ||
70 | #define WM8776_CLOCK_RATIO_512FS 4 | ||
71 | #define WM8776_CLOCK_RATIO_768FS 5 | ||
72 | |||
73 | enum { WM_VOL_HP, WM_VOL_DAC, WM_VOL_ADC, WM_NUM_VOLS }; | ||
74 | enum { WM_SW_DAC, WM_SW_BYPASS, WM_NUM_SWITCHES }; | ||
75 | |||
76 | struct snd_wm8776 { | ||
77 | unsigned char addr; | ||
78 | unsigned short regs[WM8776_NUM_REGS]; | ||
79 | unsigned char volumes[WM_NUM_VOLS][2]; | ||
80 | unsigned int switch_bits; | ||
81 | }; | ||
82 | |||
83 | struct snd_maya44 { | ||
84 | struct snd_ice1712 *ice; | ||
85 | struct snd_wm8776 wm[2]; | ||
86 | struct mutex mutex; | ||
87 | }; | ||
88 | |||
89 | |||
90 | /* write the given register and save the data to the cache */ | ||
91 | static void wm8776_write(struct snd_ice1712 *ice, struct snd_wm8776 *wm, | ||
92 | unsigned char reg, unsigned short val) | ||
93 | { | ||
94 | /* | ||
95 | * WM8776 registers are up to 9 bits wide, bit 8 is placed in the LSB | ||
96 | * of the address field | ||
97 | */ | ||
98 | snd_vt1724_write_i2c(ice, wm->addr, | ||
99 | (reg << 1) | ((val >> 8) & 1), | ||
100 | val & 0xff); | ||
101 | wm->regs[reg] = val; | ||
102 | } | ||
103 | |||
104 | /* | ||
105 | * update the given register with and/or mask and save the data to the cache | ||
106 | */ | ||
107 | static int wm8776_write_bits(struct snd_ice1712 *ice, struct snd_wm8776 *wm, | ||
108 | unsigned char reg, | ||
109 | unsigned short mask, unsigned short val) | ||
110 | { | ||
111 | val |= wm->regs[reg] & ~mask; | ||
112 | if (val != wm->regs[reg]) { | ||
113 | wm8776_write(ice, wm, reg, val); | ||
114 | return 1; | ||
115 | } | ||
116 | return 0; | ||
117 | } | ||
118 | |||
119 | |||
120 | /* | ||
121 | * WM8776 volume controls | ||
122 | */ | ||
123 | |||
124 | struct maya_vol_info { | ||
125 | unsigned int maxval; /* volume range: 0..maxval */ | ||
126 | unsigned char regs[2]; /* left and right registers */ | ||
127 | unsigned short mask; /* value mask */ | ||
128 | unsigned short offset; /* zero-value offset */ | ||
129 | unsigned short mute; /* mute bit */ | ||
130 | unsigned short update; /* update bits */ | ||
131 | unsigned char mux_bits[2]; /* extra bits for ADC mute */ | ||
132 | }; | ||
133 | |||
134 | static struct maya_vol_info vol_info[WM_NUM_VOLS] = { | ||
135 | [WM_VOL_HP] = { | ||
136 | .maxval = 80, | ||
137 | .regs = { WM8776_REG_HEADPHONE_L, WM8776_REG_HEADPHONE_R }, | ||
138 | .mask = 0x7f, | ||
139 | .offset = 0x30, | ||
140 | .mute = 0x00, | ||
141 | .update = 0x180, /* update and zero-cross enable */ | ||
142 | }, | ||
143 | [WM_VOL_DAC] = { | ||
144 | .maxval = 255, | ||
145 | .regs = { WM8776_REG_DAC_ATTEN_L, WM8776_REG_DAC_ATTEN_R }, | ||
146 | .mask = 0xff, | ||
147 | .offset = 0x01, | ||
148 | .mute = 0x00, | ||
149 | .update = 0x100, /* zero-cross enable */ | ||
150 | }, | ||
151 | [WM_VOL_ADC] = { | ||
152 | .maxval = 91, | ||
153 | .regs = { WM8776_REG_ADC_ATTEN_L, WM8776_REG_ADC_ATTEN_R }, | ||
154 | .mask = 0xff, | ||
155 | .offset = 0xa5, | ||
156 | .mute = 0xa5, | ||
157 | .update = 0x100, /* update */ | ||
158 | .mux_bits = { 0x80, 0x40 }, /* ADCMUX bits */ | ||
159 | }, | ||
160 | }; | ||
161 | |||
162 | /* | ||
163 | * dB tables | ||
164 | */ | ||
165 | /* headphone output: mute, -73..+6db (1db step) */ | ||
166 | static const DECLARE_TLV_DB_SCALE(db_scale_hp, -7400, 100, 1); | ||
167 | /* DAC output: mute, -127..0db (0.5db step) */ | ||
168 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -12750, 50, 1); | ||
169 | /* ADC gain: mute, -21..+24db (0.5db step) */ | ||
170 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, -2100, 50, 1); | ||
171 | |||
172 | static int maya_vol_info(struct snd_kcontrol *kcontrol, | ||
173 | struct snd_ctl_elem_info *uinfo) | ||
174 | { | ||
175 | unsigned int idx = kcontrol->private_value; | ||
176 | struct maya_vol_info *vol = &vol_info[idx]; | ||
177 | |||
178 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
179 | uinfo->count = 2; | ||
180 | uinfo->value.integer.min = 0; | ||
181 | uinfo->value.integer.max = vol->maxval; | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | static int maya_vol_get(struct snd_kcontrol *kcontrol, | ||
186 | struct snd_ctl_elem_value *ucontrol) | ||
187 | { | ||
188 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
189 | struct snd_wm8776 *wm = | ||
190 | &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; | ||
191 | unsigned int idx = kcontrol->private_value; | ||
192 | |||
193 | mutex_lock(&chip->mutex); | ||
194 | ucontrol->value.integer.value[0] = wm->volumes[idx][0]; | ||
195 | ucontrol->value.integer.value[1] = wm->volumes[idx][1]; | ||
196 | mutex_unlock(&chip->mutex); | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | static int maya_vol_put(struct snd_kcontrol *kcontrol, | ||
201 | struct snd_ctl_elem_value *ucontrol) | ||
202 | { | ||
203 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
204 | struct snd_wm8776 *wm = | ||
205 | &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; | ||
206 | unsigned int idx = kcontrol->private_value; | ||
207 | struct maya_vol_info *vol = &vol_info[idx]; | ||
208 | unsigned int val, data; | ||
209 | int ch, changed = 0; | ||
210 | |||
211 | mutex_lock(&chip->mutex); | ||
212 | for (ch = 0; ch < 2; ch++) { | ||
213 | val = ucontrol->value.integer.value[ch]; | ||
214 | if (val > vol->maxval) | ||
215 | val = vol->maxval; | ||
216 | if (val == wm->volumes[idx][ch]) | ||
217 | continue; | ||
218 | if (!val) | ||
219 | data = vol->mute; | ||
220 | else | ||
221 | data = (val - 1) + vol->offset; | ||
222 | data |= vol->update; | ||
223 | changed |= wm8776_write_bits(chip->ice, wm, vol->regs[ch], | ||
224 | vol->mask | vol->update, data); | ||
225 | if (vol->mux_bits[ch]) | ||
226 | wm8776_write_bits(chip->ice, wm, WM8776_REG_ADC_MUX, | ||
227 | vol->mux_bits[ch], | ||
228 | val ? 0 : vol->mux_bits[ch]); | ||
229 | wm->volumes[idx][ch] = val; | ||
230 | } | ||
231 | mutex_unlock(&chip->mutex); | ||
232 | return changed; | ||
233 | } | ||
234 | |||
235 | /* | ||
236 | * WM8776 switch controls | ||
237 | */ | ||
238 | |||
239 | #define COMPOSE_SW_VAL(idx, reg, mask) ((idx) | ((reg) << 8) | ((mask) << 16)) | ||
240 | #define GET_SW_VAL_IDX(val) ((val) & 0xff) | ||
241 | #define GET_SW_VAL_REG(val) (((val) >> 8) & 0xff) | ||
242 | #define GET_SW_VAL_MASK(val) (((val) >> 16) & 0xff) | ||
243 | |||
244 | #define maya_sw_info snd_ctl_boolean_mono_info | ||
245 | |||
246 | static int maya_sw_get(struct snd_kcontrol *kcontrol, | ||
247 | struct snd_ctl_elem_value *ucontrol) | ||
248 | { | ||
249 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
250 | struct snd_wm8776 *wm = | ||
251 | &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; | ||
252 | unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); | ||
253 | |||
254 | ucontrol->value.integer.value[0] = (wm->switch_bits >> idx) & 1; | ||
255 | return 0; | ||
256 | } | ||
257 | |||
258 | static int maya_sw_put(struct snd_kcontrol *kcontrol, | ||
259 | struct snd_ctl_elem_value *ucontrol) | ||
260 | { | ||
261 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
262 | struct snd_wm8776 *wm = | ||
263 | &chip->wm[snd_ctl_get_ioff(kcontrol, &ucontrol->id)]; | ||
264 | unsigned int idx = GET_SW_VAL_IDX(kcontrol->private_value); | ||
265 | unsigned int mask, val; | ||
266 | int changed; | ||
267 | |||
268 | mutex_lock(&chip->mutex); | ||
269 | mask = 1 << idx; | ||
270 | wm->switch_bits &= ~mask; | ||
271 | val = ucontrol->value.integer.value[0]; | ||
272 | if (val) | ||
273 | wm->switch_bits |= mask; | ||
274 | mask = GET_SW_VAL_MASK(kcontrol->private_value); | ||
275 | changed = wm8776_write_bits(chip->ice, wm, | ||
276 | GET_SW_VAL_REG(kcontrol->private_value), | ||
277 | mask, val ? mask : 0); | ||
278 | mutex_unlock(&chip->mutex); | ||
279 | return changed; | ||
280 | } | ||
281 | |||
282 | /* | ||
283 | * GPIO pins (known ones for maya44) | ||
284 | */ | ||
285 | #define GPIO_PHANTOM_OFF 2 | ||
286 | #define GPIO_MIC_RELAY 4 | ||
287 | #define GPIO_SPDIF_IN_INV 5 | ||
288 | #define GPIO_MUST_BE_0 7 | ||
289 | |||
290 | /* | ||
291 | * GPIO switch controls | ||
292 | */ | ||
293 | |||
294 | #define COMPOSE_GPIO_VAL(shift, inv) ((shift) | ((inv) << 8)) | ||
295 | #define GET_GPIO_VAL_SHIFT(val) ((val) & 0xff) | ||
296 | #define GET_GPIO_VAL_INV(val) (((val) >> 8) & 1) | ||
297 | |||
298 | static int maya_set_gpio_bits(struct snd_ice1712 *ice, unsigned int mask, | ||
299 | unsigned int bits) | ||
300 | { | ||
301 | unsigned int data; | ||
302 | data = snd_ice1712_gpio_read(ice); | ||
303 | if ((data & mask) == bits) | ||
304 | return 0; | ||
305 | snd_ice1712_gpio_write(ice, (data & ~mask) | bits); | ||
306 | return 1; | ||
307 | } | ||
308 | |||
309 | #define maya_gpio_sw_info snd_ctl_boolean_mono_info | ||
310 | |||
311 | static int maya_gpio_sw_get(struct snd_kcontrol *kcontrol, | ||
312 | struct snd_ctl_elem_value *ucontrol) | ||
313 | { | ||
314 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
315 | unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); | ||
316 | unsigned int val; | ||
317 | |||
318 | val = (snd_ice1712_gpio_read(chip->ice) >> shift) & 1; | ||
319 | if (GET_GPIO_VAL_INV(kcontrol->private_value)) | ||
320 | val = !val; | ||
321 | ucontrol->value.integer.value[0] = val; | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | static int maya_gpio_sw_put(struct snd_kcontrol *kcontrol, | ||
326 | struct snd_ctl_elem_value *ucontrol) | ||
327 | { | ||
328 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
329 | unsigned int shift = GET_GPIO_VAL_SHIFT(kcontrol->private_value); | ||
330 | unsigned int val, mask; | ||
331 | int changed; | ||
332 | |||
333 | mutex_lock(&chip->mutex); | ||
334 | mask = 1 << shift; | ||
335 | val = ucontrol->value.integer.value[0]; | ||
336 | if (GET_GPIO_VAL_INV(kcontrol->private_value)) | ||
337 | val = !val; | ||
338 | val = val ? mask : 0; | ||
339 | changed = maya_set_gpio_bits(chip->ice, mask, val); | ||
340 | mutex_unlock(&chip->mutex); | ||
341 | return changed; | ||
342 | } | ||
343 | |||
344 | /* | ||
345 | * capture source selection | ||
346 | */ | ||
347 | |||
348 | /* known working input slots (0-4) */ | ||
349 | #define MAYA_LINE_IN 1 /* in-2 */ | ||
350 | #define MAYA_MIC_IN 4 /* in-5 */ | ||
351 | |||
352 | static void wm8776_select_input(struct snd_maya44 *chip, int idx, int line) | ||
353 | { | ||
354 | wm8776_write_bits(chip->ice, &chip->wm[idx], WM8776_REG_ADC_MUX, | ||
355 | 0x1f, 1 << line); | ||
356 | } | ||
357 | |||
358 | static int maya_rec_src_info(struct snd_kcontrol *kcontrol, | ||
359 | struct snd_ctl_elem_info *uinfo) | ||
360 | { | ||
361 | static char *texts[] = { "Line", "Mic" }; | ||
362 | |||
363 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
364 | uinfo->count = 1; | ||
365 | uinfo->value.enumerated.items = ARRAY_SIZE(texts); | ||
366 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
367 | uinfo->value.enumerated.item = | ||
368 | uinfo->value.enumerated.items - 1; | ||
369 | strcpy(uinfo->value.enumerated.name, | ||
370 | texts[uinfo->value.enumerated.item]); | ||
371 | return 0; | ||
372 | } | ||
373 | |||
374 | static int maya_rec_src_get(struct snd_kcontrol *kcontrol, | ||
375 | struct snd_ctl_elem_value *ucontrol) | ||
376 | { | ||
377 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
378 | int sel; | ||
379 | |||
380 | if (snd_ice1712_gpio_read(chip->ice) & (1 << GPIO_MIC_RELAY)) | ||
381 | sel = 1; | ||
382 | else | ||
383 | sel = 0; | ||
384 | ucontrol->value.enumerated.item[0] = sel; | ||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | static int maya_rec_src_put(struct snd_kcontrol *kcontrol, | ||
389 | struct snd_ctl_elem_value *ucontrol) | ||
390 | { | ||
391 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
392 | int sel = ucontrol->value.enumerated.item[0]; | ||
393 | int changed; | ||
394 | |||
395 | mutex_lock(&chip->mutex); | ||
396 | changed = maya_set_gpio_bits(chip->ice, GPIO_MIC_RELAY, | ||
397 | sel ? GPIO_MIC_RELAY : 0); | ||
398 | wm8776_select_input(chip, 0, sel ? MAYA_MIC_IN : MAYA_LINE_IN); | ||
399 | mutex_unlock(&chip->mutex); | ||
400 | return changed; | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Maya44 routing switch settings have different meanings than the standard | ||
405 | * ice1724 switches as defined in snd_vt1724_pro_route_info (ice1724.c). | ||
406 | */ | ||
407 | static int maya_pb_route_info(struct snd_kcontrol *kcontrol, | ||
408 | struct snd_ctl_elem_info *uinfo) | ||
409 | { | ||
410 | static char *texts[] = { | ||
411 | "PCM Out", /* 0 */ | ||
412 | "Input 1", "Input 2", "Input 3", "Input 4" | ||
413 | }; | ||
414 | |||
415 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
416 | uinfo->count = 1; | ||
417 | uinfo->value.enumerated.items = ARRAY_SIZE(texts); | ||
418 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
419 | uinfo->value.enumerated.item = | ||
420 | uinfo->value.enumerated.items - 1; | ||
421 | strcpy(uinfo->value.enumerated.name, | ||
422 | texts[uinfo->value.enumerated.item]); | ||
423 | return 0; | ||
424 | } | ||
425 | |||
426 | static int maya_pb_route_shift(int idx) | ||
427 | { | ||
428 | static const unsigned char shift[10] = | ||
429 | { 8, 20, 0, 3, 11, 23, 14, 26, 17, 29 }; | ||
430 | return shift[idx % 10]; | ||
431 | } | ||
432 | |||
433 | static int maya_pb_route_get(struct snd_kcontrol *kcontrol, | ||
434 | struct snd_ctl_elem_value *ucontrol) | ||
435 | { | ||
436 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
437 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
438 | ucontrol->value.enumerated.item[0] = | ||
439 | snd_ice1724_get_route_val(chip->ice, maya_pb_route_shift(idx)); | ||
440 | return 0; | ||
441 | } | ||
442 | |||
443 | static int maya_pb_route_put(struct snd_kcontrol *kcontrol, | ||
444 | struct snd_ctl_elem_value *ucontrol) | ||
445 | { | ||
446 | struct snd_maya44 *chip = snd_kcontrol_chip(kcontrol); | ||
447 | int idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id); | ||
448 | return snd_ice1724_put_route_val(chip->ice, | ||
449 | ucontrol->value.enumerated.item[0], | ||
450 | maya_pb_route_shift(idx)); | ||
451 | } | ||
452 | |||
453 | |||
454 | /* | ||
455 | * controls to be added | ||
456 | */ | ||
457 | |||
458 | static struct snd_kcontrol_new maya_controls[] __devinitdata = { | ||
459 | { | ||
460 | .name = "Crossmix Playback Volume", | ||
461 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
462 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
463 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
464 | .info = maya_vol_info, | ||
465 | .get = maya_vol_get, | ||
466 | .put = maya_vol_put, | ||
467 | .tlv = { .p = db_scale_hp }, | ||
468 | .private_value = WM_VOL_HP, | ||
469 | .count = 2, | ||
470 | }, | ||
471 | { | ||
472 | .name = "PCM Playback Volume", | ||
473 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
474 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
475 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
476 | .info = maya_vol_info, | ||
477 | .get = maya_vol_get, | ||
478 | .put = maya_vol_put, | ||
479 | .tlv = { .p = db_scale_dac }, | ||
480 | .private_value = WM_VOL_DAC, | ||
481 | .count = 2, | ||
482 | }, | ||
483 | { | ||
484 | .name = "Line Capture Volume", | ||
485 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
486 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | | ||
487 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, | ||
488 | .info = maya_vol_info, | ||
489 | .get = maya_vol_get, | ||
490 | .put = maya_vol_put, | ||
491 | .tlv = { .p = db_scale_adc }, | ||
492 | .private_value = WM_VOL_ADC, | ||
493 | .count = 2, | ||
494 | }, | ||
495 | { | ||
496 | .name = "PCM Playback Switch", | ||
497 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
498 | .info = maya_sw_info, | ||
499 | .get = maya_sw_get, | ||
500 | .put = maya_sw_put, | ||
501 | .private_value = COMPOSE_SW_VAL(WM_SW_DAC, | ||
502 | WM8776_REG_OUTPUT_MUX, 0x01), | ||
503 | .count = 2, | ||
504 | }, | ||
505 | { | ||
506 | .name = "Bypass Playback Switch", | ||
507 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
508 | .info = maya_sw_info, | ||
509 | .get = maya_sw_get, | ||
510 | .put = maya_sw_put, | ||
511 | .private_value = COMPOSE_SW_VAL(WM_SW_BYPASS, | ||
512 | WM8776_REG_OUTPUT_MUX, 0x04), | ||
513 | .count = 2, | ||
514 | }, | ||
515 | { | ||
516 | .name = "Capture Source", | ||
517 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
518 | .info = maya_rec_src_info, | ||
519 | .get = maya_rec_src_get, | ||
520 | .put = maya_rec_src_put, | ||
521 | }, | ||
522 | { | ||
523 | .name = "Mic Phantom Power Switch", | ||
524 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
525 | .info = maya_gpio_sw_info, | ||
526 | .get = maya_gpio_sw_get, | ||
527 | .put = maya_gpio_sw_put, | ||
528 | .private_value = COMPOSE_GPIO_VAL(GPIO_PHANTOM_OFF, 1), | ||
529 | }, | ||
530 | { | ||
531 | .name = "SPDIF Capture Switch", | ||
532 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
533 | .info = maya_gpio_sw_info, | ||
534 | .get = maya_gpio_sw_get, | ||
535 | .put = maya_gpio_sw_put, | ||
536 | .private_value = COMPOSE_GPIO_VAL(GPIO_SPDIF_IN_INV, 1), | ||
537 | }, | ||
538 | { | ||
539 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
540 | .name = "H/W Playback Route", | ||
541 | .info = maya_pb_route_info, | ||
542 | .get = maya_pb_route_get, | ||
543 | .put = maya_pb_route_put, | ||
544 | .count = 4, /* FIXME: do controls 5-9 have any meaning? */ | ||
545 | }, | ||
546 | }; | ||
547 | |||
548 | static int __devinit maya44_add_controls(struct snd_ice1712 *ice) | ||
549 | { | ||
550 | int err, i; | ||
551 | |||
552 | for (i = 0; i < ARRAY_SIZE(maya_controls); i++) { | ||
553 | err = snd_ctl_add(ice->card, snd_ctl_new1(&maya_controls[i], | ||
554 | ice->spec)); | ||
555 | if (err < 0) | ||
556 | return err; | ||
557 | } | ||
558 | return 0; | ||
559 | } | ||
560 | |||
561 | |||
562 | /* | ||
563 | * initialize a wm8776 chip | ||
564 | */ | ||
565 | static void __devinit wm8776_init(struct snd_ice1712 *ice, | ||
566 | struct snd_wm8776 *wm, unsigned int addr) | ||
567 | { | ||
568 | static const unsigned short inits_wm8776[] = { | ||
569 | 0x02, 0x100, /* R2: headphone L+R muted + update */ | ||
570 | 0x05, 0x100, /* R5: DAC output L+R muted + update */ | ||
571 | 0x06, 0x000, /* R6: DAC output phase normal */ | ||
572 | 0x07, 0x091, /* R7: DAC enable zero cross detection, | ||
573 | normal output */ | ||
574 | 0x08, 0x000, /* R8: DAC soft mute off */ | ||
575 | 0x09, 0x000, /* R9: no deemph, DAC zero detect disabled */ | ||
576 | 0x0a, 0x022, /* R10: DAC I2C mode, std polarities, 24bit */ | ||
577 | 0x0b, 0x022, /* R11: ADC I2C mode, std polarities, 24bit, | ||
578 | highpass filter enabled */ | ||
579 | 0x0c, 0x042, /* R12: ADC+DAC slave, ADC+DAC 44,1kHz */ | ||
580 | 0x0d, 0x000, /* R13: all power up */ | ||
581 | 0x0e, 0x100, /* R14: ADC left muted, | ||
582 | enable zero cross detection */ | ||
583 | 0x0f, 0x100, /* R15: ADC right muted, | ||
584 | enable zero cross detection */ | ||
585 | /* R16: ALC...*/ | ||
586 | 0x11, 0x000, /* R17: disable ALC */ | ||
587 | /* R18: ALC...*/ | ||
588 | /* R19: noise gate...*/ | ||
589 | 0x15, 0x000, /* R21: ADC input mux init, mute all inputs */ | ||
590 | 0x16, 0x001, /* R22: output mux, select DAC */ | ||
591 | 0xff, 0xff | ||
592 | }; | ||
593 | |||
594 | const unsigned short *ptr; | ||
595 | unsigned char reg; | ||
596 | unsigned short data; | ||
597 | |||
598 | wm->addr = addr; | ||
599 | /* enable DAC output; mute bypass, aux & all inputs */ | ||
600 | wm->switch_bits = (1 << WM_SW_DAC); | ||
601 | |||
602 | ptr = inits_wm8776; | ||
603 | while (*ptr != 0xff) { | ||
604 | reg = *ptr++; | ||
605 | data = *ptr++; | ||
606 | wm8776_write(ice, wm, reg, data); | ||
607 | } | ||
608 | } | ||
609 | |||
610 | |||
611 | /* | ||
612 | * change the rate on the WM8776 codecs. | ||
613 | * this assumes that the VT17xx's rate is changed by the calling function. | ||
614 | * NOTE: even though the WM8776's are running in slave mode and rate | ||
615 | * selection is automatic, we need to call snd_wm8776_set_rate() here | ||
616 | * to make sure some flags are set correctly. | ||
617 | */ | ||
618 | static void set_rate(struct snd_ice1712 *ice, unsigned int rate) | ||
619 | { | ||
620 | struct snd_maya44 *chip = ice->spec; | ||
621 | unsigned int ratio, adc_ratio, val; | ||
622 | int i; | ||
623 | |||
624 | switch (rate) { | ||
625 | case 192000: | ||
626 | ratio = WM8776_CLOCK_RATIO_128FS; | ||
627 | break; | ||
628 | case 176400: | ||
629 | ratio = WM8776_CLOCK_RATIO_128FS; | ||
630 | break; | ||
631 | case 96000: | ||
632 | ratio = WM8776_CLOCK_RATIO_256FS; | ||
633 | break; | ||
634 | case 88200: | ||
635 | ratio = WM8776_CLOCK_RATIO_384FS; | ||
636 | break; | ||
637 | case 48000: | ||
638 | ratio = WM8776_CLOCK_RATIO_512FS; | ||
639 | break; | ||
640 | case 44100: | ||
641 | ratio = WM8776_CLOCK_RATIO_512FS; | ||
642 | break; | ||
643 | case 32000: | ||
644 | ratio = WM8776_CLOCK_RATIO_768FS; | ||
645 | break; | ||
646 | case 0: | ||
647 | /* no hint - S/PDIF input is master, simply return */ | ||
648 | return; | ||
649 | default: | ||
650 | snd_BUG(); | ||
651 | return; | ||
652 | } | ||
653 | |||
654 | /* | ||
655 | * this currently sets the same rate for ADC and DAC, but limits | ||
656 | * ADC rate to 256X (96kHz). For 256X mode (96kHz), this sets ADC | ||
657 | * oversampling to 64x, as recommended by WM8776 datasheet. | ||
658 | * Setting the rate is not really necessary in slave mode. | ||
659 | */ | ||
660 | adc_ratio = ratio; | ||
661 | if (adc_ratio < WM8776_CLOCK_RATIO_256FS) | ||
662 | adc_ratio = WM8776_CLOCK_RATIO_256FS; | ||
663 | |||
664 | val = adc_ratio; | ||
665 | if (adc_ratio == WM8776_CLOCK_RATIO_256FS) | ||
666 | val |= 8; | ||
667 | val |= ratio << 4; | ||
668 | |||
669 | mutex_lock(&chip->mutex); | ||
670 | for (i = 0; i < 2; i++) | ||
671 | wm8776_write_bits(ice, &chip->wm[i], | ||
672 | WM8776_REG_MASTER_MODE_CONTROL, | ||
673 | 0x180, val); | ||
674 | mutex_unlock(&chip->mutex); | ||
675 | } | ||
676 | |||
677 | /* | ||
678 | * supported sample rates (to override the default one) | ||
679 | */ | ||
680 | |||
681 | static unsigned int rates[] = { | ||
682 | 32000, 44100, 48000, 64000, 88200, 96000, 176400, 192000 | ||
683 | }; | ||
684 | |||
685 | /* playback rates: 32..192 kHz */ | ||
686 | static struct snd_pcm_hw_constraint_list dac_rates = { | ||
687 | .count = ARRAY_SIZE(rates), | ||
688 | .list = rates, | ||
689 | .mask = 0 | ||
690 | }; | ||
691 | |||
692 | |||
693 | /* | ||
694 | * chip addresses on I2C bus | ||
695 | */ | ||
696 | static unsigned char wm8776_addr[2] __devinitdata = { | ||
697 | 0x34, 0x36, /* codec 0 & 1 */ | ||
698 | }; | ||
699 | |||
700 | /* | ||
701 | * initialize the chip | ||
702 | */ | ||
703 | static int __devinit maya44_init(struct snd_ice1712 *ice) | ||
704 | { | ||
705 | int i; | ||
706 | struct snd_maya44 *chip; | ||
707 | |||
708 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
709 | if (!chip) | ||
710 | return -ENOMEM; | ||
711 | mutex_init(&chip->mutex); | ||
712 | chip->ice = ice; | ||
713 | ice->spec = chip; | ||
714 | |||
715 | /* initialise codecs */ | ||
716 | ice->num_total_dacs = 4; | ||
717 | ice->num_total_adcs = 4; | ||
718 | ice->akm_codecs = 0; | ||
719 | |||
720 | for (i = 0; i < 2; i++) { | ||
721 | wm8776_init(ice, &chip->wm[i], wm8776_addr[i]); | ||
722 | wm8776_select_input(chip, i, MAYA_LINE_IN); | ||
723 | } | ||
724 | |||
725 | /* set card specific rates */ | ||
726 | ice->hw_rates = &dac_rates; | ||
727 | |||
728 | /* register change rate notifier */ | ||
729 | ice->gpio.set_pro_rate = set_rate; | ||
730 | |||
731 | /* RDMA1 (2nd input channel) is used for ADC by default */ | ||
732 | ice->force_rdma1 = 1; | ||
733 | |||
734 | /* have an own routing control */ | ||
735 | ice->own_routing = 1; | ||
736 | |||
737 | return 0; | ||
738 | } | ||
739 | |||
740 | |||
741 | /* | ||
742 | * Maya44 boards don't provide the EEPROM data except for the vendor IDs. | ||
743 | * hence the driver needs to sets up it properly. | ||
744 | */ | ||
745 | |||
746 | static unsigned char maya44_eeprom[] __devinitdata = { | ||
747 | [ICE_EEP2_SYSCONF] = 0x45, | ||
748 | /* clock xin1=49.152MHz, mpu401, 2 stereo ADCs+DACs */ | ||
749 | [ICE_EEP2_ACLINK] = 0x80, | ||
750 | /* I2S */ | ||
751 | [ICE_EEP2_I2S] = 0xf8, | ||
752 | /* vol, 96k, 24bit, 192k */ | ||
753 | [ICE_EEP2_SPDIF] = 0xc3, | ||
754 | /* enable spdif out, spdif out supp, spdif-in, ext spdif out */ | ||
755 | [ICE_EEP2_GPIO_DIR] = 0xff, | ||
756 | [ICE_EEP2_GPIO_DIR1] = 0xff, | ||
757 | [ICE_EEP2_GPIO_DIR2] = 0xff, | ||
758 | [ICE_EEP2_GPIO_MASK] = 0/*0x9f*/, | ||
759 | [ICE_EEP2_GPIO_MASK1] = 0/*0xff*/, | ||
760 | [ICE_EEP2_GPIO_MASK2] = 0/*0x7f*/, | ||
761 | [ICE_EEP2_GPIO_STATE] = (1 << GPIO_PHANTOM_OFF) | | ||
762 | (1 << GPIO_SPDIF_IN_INV), | ||
763 | [ICE_EEP2_GPIO_STATE1] = 0x00, | ||
764 | [ICE_EEP2_GPIO_STATE2] = 0x00, | ||
765 | }; | ||
766 | |||
767 | /* entry point */ | ||
768 | struct snd_ice1712_card_info snd_vt1724_maya44_cards[] __devinitdata = { | ||
769 | { | ||
770 | .subvendor = VT1724_SUBDEVICE_MAYA44, | ||
771 | .name = "ESI Maya44", | ||
772 | .model = "maya44", | ||
773 | .chip_init = maya44_init, | ||
774 | .build_controls = maya44_add_controls, | ||
775 | .eeprom_size = sizeof(maya44_eeprom), | ||
776 | .eeprom_data = maya44_eeprom, | ||
777 | }, | ||
778 | { } /* terminator */ | ||
779 | }; | ||
diff --git a/sound/pci/ice1712/maya44.h b/sound/pci/ice1712/maya44.h new file mode 100644 index 000000000000..eafd03a8f4b5 --- /dev/null +++ b/sound/pci/ice1712/maya44.h | |||
@@ -0,0 +1,10 @@ | |||
1 | #ifndef __SOUND_MAYA44_H | ||
2 | #define __SOUND_MAYA44_H | ||
3 | |||
4 | #define MAYA44_DEVICE_DESC "{ESI,Maya44}," | ||
5 | |||
6 | #define VT1724_SUBDEVICE_MAYA44 0x34315441 /* Maya44 */ | ||
7 | |||
8 | extern struct snd_ice1712_card_info snd_vt1724_maya44_cards[]; | ||
9 | |||
10 | #endif /* __SOUND_MAYA44_H */ | ||
diff --git a/sound/pci/lx6464es/Makefile b/sound/pci/lx6464es/Makefile new file mode 100644 index 000000000000..eb04a6c73d8b --- /dev/null +++ b/sound/pci/lx6464es/Makefile | |||
@@ -0,0 +1,2 @@ | |||
1 | snd-lx6464es-objs := lx6464es.o lx_core.o | ||
2 | obj-$(CONFIG_SND_LX6464ES) += snd-lx6464es.o | ||
diff --git a/sound/pci/lx6464es/lx6464es.c b/sound/pci/lx6464es/lx6464es.c new file mode 100644 index 000000000000..ccf1b38c88ea --- /dev/null +++ b/sound/pci/lx6464es/lx6464es.c | |||
@@ -0,0 +1,1159 @@ | |||
1 | /* -*- linux-c -*- * | ||
2 | * | ||
3 | * ALSA driver for the digigram lx6464es interface | ||
4 | * | ||
5 | * Copyright (c) 2008, 2009 Tim Blechmann <tim@klingt.org> | ||
6 | * | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, write to | ||
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
21 | * Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #include <linux/module.h> | ||
26 | #include <linux/init.h> | ||
27 | #include <linux/pci.h> | ||
28 | #include <linux/delay.h> | ||
29 | |||
30 | #include <sound/initval.h> | ||
31 | #include <sound/control.h> | ||
32 | #include <sound/info.h> | ||
33 | |||
34 | #include "lx6464es.h" | ||
35 | |||
36 | MODULE_AUTHOR("Tim Blechmann"); | ||
37 | MODULE_LICENSE("GPL"); | ||
38 | MODULE_DESCRIPTION("digigram lx6464es"); | ||
39 | MODULE_SUPPORTED_DEVICE("{digigram lx6464es{}}"); | ||
40 | |||
41 | |||
42 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | ||
43 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | ||
44 | static int enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | ||
45 | |||
46 | module_param_array(index, int, NULL, 0444); | ||
47 | MODULE_PARM_DESC(index, "Index value for Digigram LX6464ES interface."); | ||
48 | module_param_array(id, charp, NULL, 0444); | ||
49 | MODULE_PARM_DESC(id, "ID string for Digigram LX6464ES interface."); | ||
50 | module_param_array(enable, bool, NULL, 0444); | ||
51 | MODULE_PARM_DESC(enable, "Enable/disable specific Digigram LX6464ES soundcards."); | ||
52 | |||
53 | static const char card_name[] = "LX6464ES"; | ||
54 | |||
55 | |||
56 | #define PCI_DEVICE_ID_PLX_LX6464ES PCI_DEVICE_ID_PLX_9056 | ||
57 | |||
58 | static struct pci_device_id snd_lx6464es_ids[] = { | ||
59 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), | ||
60 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, | ||
61 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_SERIAL_SUBSYSTEM | ||
62 | }, /* LX6464ES */ | ||
63 | { PCI_DEVICE(PCI_VENDOR_ID_PLX, PCI_DEVICE_ID_PLX_LX6464ES), | ||
64 | .subvendor = PCI_VENDOR_ID_DIGIGRAM, | ||
65 | .subdevice = PCI_SUBDEVICE_ID_DIGIGRAM_LX6464ES_CAE_SERIAL_SUBSYSTEM | ||
66 | }, /* LX6464ES-CAE */ | ||
67 | { 0, }, | ||
68 | }; | ||
69 | |||
70 | MODULE_DEVICE_TABLE(pci, snd_lx6464es_ids); | ||
71 | |||
72 | |||
73 | |||
74 | /* PGO pour USERo dans le registre pci_0x06/loc_0xEC */ | ||
75 | #define CHIPSC_RESET_XILINX (1L<<16) | ||
76 | |||
77 | |||
78 | /* alsa callbacks */ | ||
79 | static struct snd_pcm_hardware lx_caps = { | ||
80 | .info = (SNDRV_PCM_INFO_MMAP | | ||
81 | SNDRV_PCM_INFO_INTERLEAVED | | ||
82 | SNDRV_PCM_INFO_MMAP_VALID | | ||
83 | SNDRV_PCM_INFO_SYNC_START), | ||
84 | .formats = (SNDRV_PCM_FMTBIT_S16_LE | | ||
85 | SNDRV_PCM_FMTBIT_S16_BE | | ||
86 | SNDRV_PCM_FMTBIT_S24_3LE | | ||
87 | SNDRV_PCM_FMTBIT_S24_3BE), | ||
88 | .rates = (SNDRV_PCM_RATE_CONTINUOUS | | ||
89 | SNDRV_PCM_RATE_8000_192000), | ||
90 | .rate_min = 8000, | ||
91 | .rate_max = 192000, | ||
92 | .channels_min = 2, | ||
93 | .channels_max = 64, | ||
94 | .buffer_bytes_max = 64*2*3*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER, | ||
95 | .period_bytes_min = (2*2*MICROBLAZE_IBL_MIN*2), | ||
96 | .period_bytes_max = (4*64*MICROBLAZE_IBL_MAX*MAX_STREAM_BUFFER), | ||
97 | .periods_min = 2, | ||
98 | .periods_max = MAX_STREAM_BUFFER, | ||
99 | }; | ||
100 | |||
101 | static int lx_set_granularity(struct lx6464es *chip, u32 gran); | ||
102 | |||
103 | |||
104 | static int lx_hardware_open(struct lx6464es *chip, | ||
105 | struct snd_pcm_substream *substream) | ||
106 | { | ||
107 | int err = 0; | ||
108 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
109 | int channels = runtime->channels; | ||
110 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
111 | |||
112 | snd_pcm_uframes_t period_size = runtime->period_size; | ||
113 | |||
114 | snd_printd(LXP "allocating pipe for %d channels\n", channels); | ||
115 | err = lx_pipe_allocate(chip, 0, is_capture, channels); | ||
116 | if (err < 0) { | ||
117 | snd_printk(KERN_ERR LXP "allocating pipe failed\n"); | ||
118 | return err; | ||
119 | } | ||
120 | |||
121 | err = lx_set_granularity(chip, period_size); | ||
122 | if (err < 0) { | ||
123 | snd_printk(KERN_ERR LXP "setting granularity to %ld failed\n", | ||
124 | period_size); | ||
125 | return err; | ||
126 | } | ||
127 | |||
128 | return 0; | ||
129 | } | ||
130 | |||
131 | static int lx_hardware_start(struct lx6464es *chip, | ||
132 | struct snd_pcm_substream *substream) | ||
133 | { | ||
134 | int err = 0; | ||
135 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
136 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
137 | |||
138 | snd_printd(LXP "setting stream format\n"); | ||
139 | err = lx_stream_set_format(chip, runtime, 0, is_capture); | ||
140 | if (err < 0) { | ||
141 | snd_printk(KERN_ERR LXP "setting stream format failed\n"); | ||
142 | return err; | ||
143 | } | ||
144 | |||
145 | snd_printd(LXP "starting pipe\n"); | ||
146 | err = lx_pipe_start(chip, 0, is_capture); | ||
147 | if (err < 0) { | ||
148 | snd_printk(KERN_ERR LXP "starting pipe failed\n"); | ||
149 | return err; | ||
150 | } | ||
151 | |||
152 | snd_printd(LXP "waiting for pipe to start\n"); | ||
153 | err = lx_pipe_wait_for_start(chip, 0, is_capture); | ||
154 | if (err < 0) { | ||
155 | snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); | ||
156 | return err; | ||
157 | } | ||
158 | |||
159 | return err; | ||
160 | } | ||
161 | |||
162 | |||
163 | static int lx_hardware_stop(struct lx6464es *chip, | ||
164 | struct snd_pcm_substream *substream) | ||
165 | { | ||
166 | int err = 0; | ||
167 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
168 | |||
169 | snd_printd(LXP "pausing pipe\n"); | ||
170 | err = lx_pipe_pause(chip, 0, is_capture); | ||
171 | if (err < 0) { | ||
172 | snd_printk(KERN_ERR LXP "pausing pipe failed\n"); | ||
173 | return err; | ||
174 | } | ||
175 | |||
176 | snd_printd(LXP "waiting for pipe to become idle\n"); | ||
177 | err = lx_pipe_wait_for_idle(chip, 0, is_capture); | ||
178 | if (err < 0) { | ||
179 | snd_printk(KERN_ERR LXP "waiting for pipe failed\n"); | ||
180 | return err; | ||
181 | } | ||
182 | |||
183 | snd_printd(LXP "stopping pipe\n"); | ||
184 | err = lx_pipe_stop(chip, 0, is_capture); | ||
185 | if (err < 0) { | ||
186 | snd_printk(LXP "stopping pipe failed\n"); | ||
187 | return err; | ||
188 | } | ||
189 | |||
190 | return err; | ||
191 | } | ||
192 | |||
193 | |||
194 | static int lx_hardware_close(struct lx6464es *chip, | ||
195 | struct snd_pcm_substream *substream) | ||
196 | { | ||
197 | int err = 0; | ||
198 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
199 | |||
200 | snd_printd(LXP "releasing pipe\n"); | ||
201 | err = lx_pipe_release(chip, 0, is_capture); | ||
202 | if (err < 0) { | ||
203 | snd_printk(LXP "releasing pipe failed\n"); | ||
204 | return err; | ||
205 | } | ||
206 | |||
207 | return err; | ||
208 | } | ||
209 | |||
210 | |||
211 | static int lx_pcm_open(struct snd_pcm_substream *substream) | ||
212 | { | ||
213 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
214 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
215 | int err = 0; | ||
216 | int board_rate; | ||
217 | |||
218 | snd_printdd("->lx_pcm_open\n"); | ||
219 | mutex_lock(&chip->setup_mutex); | ||
220 | |||
221 | /* copy the struct snd_pcm_hardware struct */ | ||
222 | runtime->hw = lx_caps; | ||
223 | |||
224 | #if 0 | ||
225 | /* buffer-size should better be multiple of period-size */ | ||
226 | err = snd_pcm_hw_constraint_integer(runtime, | ||
227 | SNDRV_PCM_HW_PARAM_PERIODS); | ||
228 | if (err < 0) { | ||
229 | snd_printk(KERN_WARNING LXP "could not constrain periods\n"); | ||
230 | goto exit; | ||
231 | } | ||
232 | #endif | ||
233 | |||
234 | /* the clock rate cannot be changed */ | ||
235 | board_rate = chip->board_sample_rate; | ||
236 | err = snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_RATE, | ||
237 | board_rate, board_rate); | ||
238 | |||
239 | if (err < 0) { | ||
240 | snd_printk(KERN_WARNING LXP "could not constrain periods\n"); | ||
241 | goto exit; | ||
242 | } | ||
243 | |||
244 | /* constrain period size */ | ||
245 | err = snd_pcm_hw_constraint_minmax(runtime, | ||
246 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
247 | MICROBLAZE_IBL_MIN, | ||
248 | MICROBLAZE_IBL_MAX); | ||
249 | if (err < 0) { | ||
250 | snd_printk(KERN_WARNING LXP | ||
251 | "could not constrain period size\n"); | ||
252 | goto exit; | ||
253 | } | ||
254 | |||
255 | snd_pcm_hw_constraint_step(runtime, 0, | ||
256 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, 32); | ||
257 | |||
258 | snd_pcm_set_sync(substream); | ||
259 | err = 0; | ||
260 | |||
261 | exit: | ||
262 | runtime->private_data = chip; | ||
263 | |||
264 | mutex_unlock(&chip->setup_mutex); | ||
265 | snd_printdd("<-lx_pcm_open, %d\n", err); | ||
266 | return err; | ||
267 | } | ||
268 | |||
269 | static int lx_pcm_close(struct snd_pcm_substream *substream) | ||
270 | { | ||
271 | int err = 0; | ||
272 | snd_printdd("->lx_pcm_close\n"); | ||
273 | return err; | ||
274 | } | ||
275 | |||
276 | static snd_pcm_uframes_t lx_pcm_stream_pointer(struct snd_pcm_substream | ||
277 | *substream) | ||
278 | { | ||
279 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
280 | snd_pcm_uframes_t pos; | ||
281 | unsigned long flags; | ||
282 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
283 | |||
284 | struct lx_stream *lx_stream = is_capture ? &chip->capture_stream : | ||
285 | &chip->playback_stream; | ||
286 | |||
287 | snd_printdd("->lx_pcm_stream_pointer\n"); | ||
288 | |||
289 | spin_lock_irqsave(&chip->lock, flags); | ||
290 | pos = lx_stream->frame_pos * substream->runtime->period_size; | ||
291 | spin_unlock_irqrestore(&chip->lock, flags); | ||
292 | |||
293 | snd_printdd(LXP "stream_pointer at %ld\n", pos); | ||
294 | return pos; | ||
295 | } | ||
296 | |||
297 | static int lx_pcm_prepare(struct snd_pcm_substream *substream) | ||
298 | { | ||
299 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
300 | int err = 0; | ||
301 | const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
302 | |||
303 | snd_printdd("->lx_pcm_prepare\n"); | ||
304 | |||
305 | mutex_lock(&chip->setup_mutex); | ||
306 | |||
307 | if (chip->hardware_running[is_capture]) { | ||
308 | err = lx_hardware_stop(chip, substream); | ||
309 | if (err < 0) { | ||
310 | snd_printk(KERN_ERR LXP "failed to stop hardware. " | ||
311 | "Error code %d\n", err); | ||
312 | goto exit; | ||
313 | } | ||
314 | |||
315 | err = lx_hardware_close(chip, substream); | ||
316 | if (err < 0) { | ||
317 | snd_printk(KERN_ERR LXP "failed to close hardware. " | ||
318 | "Error code %d\n", err); | ||
319 | goto exit; | ||
320 | } | ||
321 | } | ||
322 | |||
323 | snd_printd(LXP "opening hardware\n"); | ||
324 | err = lx_hardware_open(chip, substream); | ||
325 | if (err < 0) { | ||
326 | snd_printk(KERN_ERR LXP "failed to open hardware. " | ||
327 | "Error code %d\n", err); | ||
328 | goto exit; | ||
329 | } | ||
330 | |||
331 | err = lx_hardware_start(chip, substream); | ||
332 | if (err < 0) { | ||
333 | snd_printk(KERN_ERR LXP "failed to start hardware. " | ||
334 | "Error code %d\n", err); | ||
335 | goto exit; | ||
336 | } | ||
337 | |||
338 | chip->hardware_running[is_capture] = 1; | ||
339 | |||
340 | if (chip->board_sample_rate != substream->runtime->rate) { | ||
341 | if (!err) | ||
342 | chip->board_sample_rate = substream->runtime->rate; | ||
343 | } | ||
344 | |||
345 | exit: | ||
346 | mutex_unlock(&chip->setup_mutex); | ||
347 | return err; | ||
348 | } | ||
349 | |||
350 | static int lx_pcm_hw_params(struct snd_pcm_substream *substream, | ||
351 | struct snd_pcm_hw_params *hw_params, int is_capture) | ||
352 | { | ||
353 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
354 | int err = 0; | ||
355 | |||
356 | snd_printdd("->lx_pcm_hw_params\n"); | ||
357 | |||
358 | mutex_lock(&chip->setup_mutex); | ||
359 | |||
360 | /* set dma buffer */ | ||
361 | err = snd_pcm_lib_malloc_pages(substream, | ||
362 | params_buffer_bytes(hw_params)); | ||
363 | |||
364 | if (is_capture) | ||
365 | chip->capture_stream.stream = substream; | ||
366 | else | ||
367 | chip->playback_stream.stream = substream; | ||
368 | |||
369 | mutex_unlock(&chip->setup_mutex); | ||
370 | return err; | ||
371 | } | ||
372 | |||
373 | static int lx_pcm_hw_params_playback(struct snd_pcm_substream *substream, | ||
374 | struct snd_pcm_hw_params *hw_params) | ||
375 | { | ||
376 | return lx_pcm_hw_params(substream, hw_params, 0); | ||
377 | } | ||
378 | |||
379 | static int lx_pcm_hw_params_capture(struct snd_pcm_substream *substream, | ||
380 | struct snd_pcm_hw_params *hw_params) | ||
381 | { | ||
382 | return lx_pcm_hw_params(substream, hw_params, 1); | ||
383 | } | ||
384 | |||
385 | static int lx_pcm_hw_free(struct snd_pcm_substream *substream) | ||
386 | { | ||
387 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
388 | int err = 0; | ||
389 | int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
390 | |||
391 | snd_printdd("->lx_pcm_hw_free\n"); | ||
392 | mutex_lock(&chip->setup_mutex); | ||
393 | |||
394 | if (chip->hardware_running[is_capture]) { | ||
395 | err = lx_hardware_stop(chip, substream); | ||
396 | if (err < 0) { | ||
397 | snd_printk(KERN_ERR LXP "failed to stop hardware. " | ||
398 | "Error code %d\n", err); | ||
399 | goto exit; | ||
400 | } | ||
401 | |||
402 | err = lx_hardware_close(chip, substream); | ||
403 | if (err < 0) { | ||
404 | snd_printk(KERN_ERR LXP "failed to close hardware. " | ||
405 | "Error code %d\n", err); | ||
406 | goto exit; | ||
407 | } | ||
408 | |||
409 | chip->hardware_running[is_capture] = 0; | ||
410 | } | ||
411 | |||
412 | err = snd_pcm_lib_free_pages(substream); | ||
413 | |||
414 | if (is_capture) | ||
415 | chip->capture_stream.stream = 0; | ||
416 | else | ||
417 | chip->playback_stream.stream = 0; | ||
418 | |||
419 | exit: | ||
420 | mutex_unlock(&chip->setup_mutex); | ||
421 | return err; | ||
422 | } | ||
423 | |||
424 | static void lx_trigger_start(struct lx6464es *chip, struct lx_stream *lx_stream) | ||
425 | { | ||
426 | struct snd_pcm_substream *substream = lx_stream->stream; | ||
427 | const int is_capture = lx_stream->is_capture; | ||
428 | |||
429 | int err; | ||
430 | |||
431 | const u32 channels = substream->runtime->channels; | ||
432 | const u32 bytes_per_frame = channels * 3; | ||
433 | const u32 period_size = substream->runtime->period_size; | ||
434 | const u32 periods = substream->runtime->periods; | ||
435 | const u32 period_bytes = period_size * bytes_per_frame; | ||
436 | |||
437 | dma_addr_t buf = substream->dma_buffer.addr; | ||
438 | int i; | ||
439 | |||
440 | u32 needed, freed; | ||
441 | u32 size_array[5]; | ||
442 | |||
443 | for (i = 0; i != periods; ++i) { | ||
444 | u32 buffer_index = 0; | ||
445 | |||
446 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, | ||
447 | size_array); | ||
448 | snd_printdd(LXP "starting: needed %d, freed %d\n", | ||
449 | needed, freed); | ||
450 | |||
451 | err = lx_buffer_give(chip, 0, is_capture, period_bytes, | ||
452 | lower_32_bits(buf), upper_32_bits(buf), | ||
453 | &buffer_index); | ||
454 | |||
455 | snd_printdd(LXP "starting: buffer index %x on %p (%d bytes)\n", | ||
456 | buffer_index, (void *)buf, period_bytes); | ||
457 | buf += period_bytes; | ||
458 | } | ||
459 | |||
460 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); | ||
461 | snd_printdd(LXP "starting: needed %d, freed %d\n", needed, freed); | ||
462 | |||
463 | snd_printd(LXP "starting: starting stream\n"); | ||
464 | err = lx_stream_start(chip, 0, is_capture); | ||
465 | if (err < 0) | ||
466 | snd_printk(KERN_ERR LXP "couldn't start stream\n"); | ||
467 | else | ||
468 | lx_stream->status = LX_STREAM_STATUS_RUNNING; | ||
469 | |||
470 | lx_stream->frame_pos = 0; | ||
471 | } | ||
472 | |||
473 | static void lx_trigger_stop(struct lx6464es *chip, struct lx_stream *lx_stream) | ||
474 | { | ||
475 | const int is_capture = lx_stream->is_capture; | ||
476 | int err; | ||
477 | |||
478 | snd_printd(LXP "stopping: stopping stream\n"); | ||
479 | err = lx_stream_stop(chip, 0, is_capture); | ||
480 | if (err < 0) | ||
481 | snd_printk(KERN_ERR LXP "couldn't stop stream\n"); | ||
482 | else | ||
483 | lx_stream->status = LX_STREAM_STATUS_FREE; | ||
484 | |||
485 | } | ||
486 | |||
487 | static void lx_trigger_tasklet_dispatch_stream(struct lx6464es *chip, | ||
488 | struct lx_stream *lx_stream) | ||
489 | { | ||
490 | switch (lx_stream->status) { | ||
491 | case LX_STREAM_STATUS_SCHEDULE_RUN: | ||
492 | lx_trigger_start(chip, lx_stream); | ||
493 | break; | ||
494 | |||
495 | case LX_STREAM_STATUS_SCHEDULE_STOP: | ||
496 | lx_trigger_stop(chip, lx_stream); | ||
497 | break; | ||
498 | |||
499 | default: | ||
500 | break; | ||
501 | } | ||
502 | } | ||
503 | |||
504 | static void lx_trigger_tasklet(unsigned long data) | ||
505 | { | ||
506 | struct lx6464es *chip = (struct lx6464es *)data; | ||
507 | unsigned long flags; | ||
508 | |||
509 | snd_printdd("->lx_trigger_tasklet\n"); | ||
510 | |||
511 | spin_lock_irqsave(&chip->lock, flags); | ||
512 | lx_trigger_tasklet_dispatch_stream(chip, &chip->capture_stream); | ||
513 | lx_trigger_tasklet_dispatch_stream(chip, &chip->playback_stream); | ||
514 | spin_unlock_irqrestore(&chip->lock, flags); | ||
515 | } | ||
516 | |||
517 | static int lx_pcm_trigger_dispatch(struct lx6464es *chip, | ||
518 | struct lx_stream *lx_stream, int cmd) | ||
519 | { | ||
520 | int err = 0; | ||
521 | |||
522 | switch (cmd) { | ||
523 | case SNDRV_PCM_TRIGGER_START: | ||
524 | lx_stream->status = LX_STREAM_STATUS_SCHEDULE_RUN; | ||
525 | break; | ||
526 | |||
527 | case SNDRV_PCM_TRIGGER_STOP: | ||
528 | lx_stream->status = LX_STREAM_STATUS_SCHEDULE_STOP; | ||
529 | break; | ||
530 | |||
531 | default: | ||
532 | err = -EINVAL; | ||
533 | goto exit; | ||
534 | } | ||
535 | tasklet_schedule(&chip->trigger_tasklet); | ||
536 | |||
537 | exit: | ||
538 | return err; | ||
539 | } | ||
540 | |||
541 | |||
542 | static int lx_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | ||
543 | { | ||
544 | struct lx6464es *chip = snd_pcm_substream_chip(substream); | ||
545 | const int is_capture = (substream->stream == SNDRV_PCM_STREAM_CAPTURE); | ||
546 | struct lx_stream *stream = is_capture ? &chip->capture_stream : | ||
547 | &chip->playback_stream; | ||
548 | |||
549 | snd_printdd("->lx_pcm_trigger\n"); | ||
550 | |||
551 | return lx_pcm_trigger_dispatch(chip, stream, cmd); | ||
552 | } | ||
553 | |||
554 | static int snd_lx6464es_free(struct lx6464es *chip) | ||
555 | { | ||
556 | snd_printdd("->snd_lx6464es_free\n"); | ||
557 | |||
558 | lx_irq_disable(chip); | ||
559 | |||
560 | if (chip->irq >= 0) | ||
561 | free_irq(chip->irq, chip); | ||
562 | |||
563 | iounmap(chip->port_dsp_bar); | ||
564 | ioport_unmap(chip->port_plx_remapped); | ||
565 | |||
566 | pci_release_regions(chip->pci); | ||
567 | pci_disable_device(chip->pci); | ||
568 | |||
569 | kfree(chip); | ||
570 | |||
571 | return 0; | ||
572 | } | ||
573 | |||
574 | static int snd_lx6464es_dev_free(struct snd_device *device) | ||
575 | { | ||
576 | return snd_lx6464es_free(device->device_data); | ||
577 | } | ||
578 | |||
579 | /* reset the dsp during initialization */ | ||
580 | static int __devinit lx_init_xilinx_reset(struct lx6464es *chip) | ||
581 | { | ||
582 | int i; | ||
583 | u32 plx_reg = lx_plx_reg_read(chip, ePLX_CHIPSC); | ||
584 | |||
585 | snd_printdd("->lx_init_xilinx_reset\n"); | ||
586 | |||
587 | /* activate reset of xilinx */ | ||
588 | plx_reg &= ~CHIPSC_RESET_XILINX; | ||
589 | |||
590 | lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); | ||
591 | msleep(1); | ||
592 | |||
593 | lx_plx_reg_write(chip, ePLX_MBOX3, 0); | ||
594 | msleep(1); | ||
595 | |||
596 | plx_reg |= CHIPSC_RESET_XILINX; | ||
597 | lx_plx_reg_write(chip, ePLX_CHIPSC, plx_reg); | ||
598 | |||
599 | /* deactivate reset of xilinx */ | ||
600 | for (i = 0; i != 100; ++i) { | ||
601 | u32 reg_mbox3; | ||
602 | msleep(10); | ||
603 | reg_mbox3 = lx_plx_reg_read(chip, ePLX_MBOX3); | ||
604 | if (reg_mbox3) { | ||
605 | snd_printd(LXP "xilinx reset done\n"); | ||
606 | snd_printdd(LXP "xilinx took %d loops\n", i); | ||
607 | break; | ||
608 | } | ||
609 | } | ||
610 | |||
611 | /* todo: add some error handling? */ | ||
612 | |||
613 | /* clear mr */ | ||
614 | lx_dsp_reg_write(chip, eReg_CSM, 0); | ||
615 | |||
616 | /* le xilinx ES peut ne pas etre encore pret, on attend. */ | ||
617 | msleep(600); | ||
618 | |||
619 | return 0; | ||
620 | } | ||
621 | |||
622 | static int __devinit lx_init_xilinx_test(struct lx6464es *chip) | ||
623 | { | ||
624 | u32 reg; | ||
625 | |||
626 | snd_printdd("->lx_init_xilinx_test\n"); | ||
627 | |||
628 | /* TEST if we have access to Xilinx/MicroBlaze */ | ||
629 | lx_dsp_reg_write(chip, eReg_CSM, 0); | ||
630 | |||
631 | reg = lx_dsp_reg_read(chip, eReg_CSM); | ||
632 | |||
633 | if (reg) { | ||
634 | snd_printk(KERN_ERR LXP "Problem: Reg_CSM %x.\n", reg); | ||
635 | |||
636 | /* PCI9056_SPACE0_REMAP */ | ||
637 | lx_plx_reg_write(chip, ePLX_PCICR, 1); | ||
638 | |||
639 | reg = lx_dsp_reg_read(chip, eReg_CSM); | ||
640 | if (reg) { | ||
641 | snd_printk(KERN_ERR LXP "Error: Reg_CSM %x.\n", reg); | ||
642 | return -EAGAIN; /* seems to be appropriate */ | ||
643 | } | ||
644 | } | ||
645 | |||
646 | snd_printd(LXP "Xilinx/MicroBlaze access test successful\n"); | ||
647 | |||
648 | return 0; | ||
649 | } | ||
650 | |||
651 | /* initialize ethersound */ | ||
652 | static int __devinit lx_init_ethersound_config(struct lx6464es *chip) | ||
653 | { | ||
654 | int i; | ||
655 | u32 orig_conf_es = lx_dsp_reg_read(chip, eReg_CONFES); | ||
656 | |||
657 | u32 default_conf_es = (64 << IOCR_OUTPUTS_OFFSET) | | ||
658 | (64 << IOCR_INPUTS_OFFSET) | | ||
659 | (FREQ_RATIO_SINGLE_MODE << FREQ_RATIO_OFFSET); | ||
660 | |||
661 | u32 conf_es = (orig_conf_es & CONFES_READ_PART_MASK) | ||
662 | | (default_conf_es & CONFES_WRITE_PART_MASK); | ||
663 | |||
664 | snd_printdd("->lx_init_ethersound\n"); | ||
665 | |||
666 | chip->freq_ratio = FREQ_RATIO_SINGLE_MODE; | ||
667 | |||
668 | /* | ||
669 | * write it to the card ! | ||
670 | * this actually kicks the ES xilinx, the first time since poweron. | ||
671 | * the MAC address in the Reg_ADMACESMSB Reg_ADMACESLSB registers | ||
672 | * is not ready before this is done, and the bit 2 in Reg_CSES is set. | ||
673 | * */ | ||
674 | lx_dsp_reg_write(chip, eReg_CONFES, conf_es); | ||
675 | |||
676 | for (i = 0; i != 1000; ++i) { | ||
677 | if (lx_dsp_reg_read(chip, eReg_CSES) & 4) { | ||
678 | snd_printd(LXP "ethersound initialized after %dms\n", | ||
679 | i); | ||
680 | goto ethersound_initialized; | ||
681 | } | ||
682 | msleep(1); | ||
683 | } | ||
684 | snd_printk(KERN_WARNING LXP | ||
685 | "ethersound could not be initialized after %dms\n", i); | ||
686 | return -ETIMEDOUT; | ||
687 | |||
688 | ethersound_initialized: | ||
689 | snd_printd(LXP "ethersound initialized\n"); | ||
690 | return 0; | ||
691 | } | ||
692 | |||
693 | static int __devinit lx_init_get_version_features(struct lx6464es *chip) | ||
694 | { | ||
695 | u32 dsp_version; | ||
696 | |||
697 | int err; | ||
698 | |||
699 | snd_printdd("->lx_init_get_version_features\n"); | ||
700 | |||
701 | err = lx_dsp_get_version(chip, &dsp_version); | ||
702 | |||
703 | if (err == 0) { | ||
704 | u32 freq; | ||
705 | |||
706 | snd_printk(LXP "DSP version: V%02d.%02d #%d\n", | ||
707 | (dsp_version>>16) & 0xff, (dsp_version>>8) & 0xff, | ||
708 | dsp_version & 0xff); | ||
709 | |||
710 | /* later: what firmware version do we expect? */ | ||
711 | |||
712 | /* retrieve Play/Rec features */ | ||
713 | /* done here because we may have to handle alternate | ||
714 | * DSP files. */ | ||
715 | /* later */ | ||
716 | |||
717 | /* init the EtherSound sample rate */ | ||
718 | err = lx_dsp_get_clock_frequency(chip, &freq); | ||
719 | if (err == 0) | ||
720 | chip->board_sample_rate = freq; | ||
721 | snd_printd(LXP "actual clock frequency %d\n", freq); | ||
722 | } else { | ||
723 | snd_printk(KERN_ERR LXP "DSP corrupted \n"); | ||
724 | err = -EAGAIN; | ||
725 | } | ||
726 | |||
727 | return err; | ||
728 | } | ||
729 | |||
730 | static int lx_set_granularity(struct lx6464es *chip, u32 gran) | ||
731 | { | ||
732 | int err = 0; | ||
733 | u32 snapped_gran = MICROBLAZE_IBL_MIN; | ||
734 | |||
735 | snd_printdd("->lx_set_granularity\n"); | ||
736 | |||
737 | /* blocksize is a power of 2 */ | ||
738 | while ((snapped_gran < gran) && | ||
739 | (snapped_gran < MICROBLAZE_IBL_MAX)) { | ||
740 | snapped_gran *= 2; | ||
741 | } | ||
742 | |||
743 | if (snapped_gran == chip->pcm_granularity) | ||
744 | return 0; | ||
745 | |||
746 | err = lx_dsp_set_granularity(chip, snapped_gran); | ||
747 | if (err < 0) { | ||
748 | snd_printk(KERN_WARNING LXP "could not set granularity\n"); | ||
749 | err = -EAGAIN; | ||
750 | } | ||
751 | |||
752 | if (snapped_gran != gran) | ||
753 | snd_printk(LXP "snapped blocksize to %d\n", snapped_gran); | ||
754 | |||
755 | snd_printd(LXP "set blocksize on board %d\n", snapped_gran); | ||
756 | chip->pcm_granularity = snapped_gran; | ||
757 | |||
758 | return err; | ||
759 | } | ||
760 | |||
761 | /* initialize and test the xilinx dsp chip */ | ||
762 | static int __devinit lx_init_dsp(struct lx6464es *chip) | ||
763 | { | ||
764 | int err; | ||
765 | u8 mac_address[6]; | ||
766 | int i; | ||
767 | |||
768 | snd_printdd("->lx_init_dsp\n"); | ||
769 | |||
770 | snd_printd(LXP "initialize board\n"); | ||
771 | err = lx_init_xilinx_reset(chip); | ||
772 | if (err) | ||
773 | return err; | ||
774 | |||
775 | snd_printd(LXP "testing board\n"); | ||
776 | err = lx_init_xilinx_test(chip); | ||
777 | if (err) | ||
778 | return err; | ||
779 | |||
780 | snd_printd(LXP "initialize ethersound configuration\n"); | ||
781 | err = lx_init_ethersound_config(chip); | ||
782 | if (err) | ||
783 | return err; | ||
784 | |||
785 | lx_irq_enable(chip); | ||
786 | |||
787 | /** \todo the mac address should be ready by not, but it isn't, | ||
788 | * so we wait for it */ | ||
789 | for (i = 0; i != 1000; ++i) { | ||
790 | err = lx_dsp_get_mac(chip, mac_address); | ||
791 | if (err) | ||
792 | return err; | ||
793 | if (mac_address[0] || mac_address[1] || mac_address[2] || | ||
794 | mac_address[3] || mac_address[4] || mac_address[5]) | ||
795 | goto mac_ready; | ||
796 | msleep(1); | ||
797 | } | ||
798 | return -ETIMEDOUT; | ||
799 | |||
800 | mac_ready: | ||
801 | snd_printd(LXP "mac address ready read after: %dms\n", i); | ||
802 | snd_printk(LXP "mac address: %02X.%02X.%02X.%02X.%02X.%02X\n", | ||
803 | mac_address[0], mac_address[1], mac_address[2], | ||
804 | mac_address[3], mac_address[4], mac_address[5]); | ||
805 | |||
806 | err = lx_init_get_version_features(chip); | ||
807 | if (err) | ||
808 | return err; | ||
809 | |||
810 | lx_set_granularity(chip, MICROBLAZE_IBL_DEFAULT); | ||
811 | |||
812 | chip->playback_mute = 0; | ||
813 | |||
814 | return err; | ||
815 | } | ||
816 | |||
817 | static struct snd_pcm_ops lx_ops_playback = { | ||
818 | .open = lx_pcm_open, | ||
819 | .close = lx_pcm_close, | ||
820 | .ioctl = snd_pcm_lib_ioctl, | ||
821 | .prepare = lx_pcm_prepare, | ||
822 | .hw_params = lx_pcm_hw_params_playback, | ||
823 | .hw_free = lx_pcm_hw_free, | ||
824 | .trigger = lx_pcm_trigger, | ||
825 | .pointer = lx_pcm_stream_pointer, | ||
826 | }; | ||
827 | |||
828 | static struct snd_pcm_ops lx_ops_capture = { | ||
829 | .open = lx_pcm_open, | ||
830 | .close = lx_pcm_close, | ||
831 | .ioctl = snd_pcm_lib_ioctl, | ||
832 | .prepare = lx_pcm_prepare, | ||
833 | .hw_params = lx_pcm_hw_params_capture, | ||
834 | .hw_free = lx_pcm_hw_free, | ||
835 | .trigger = lx_pcm_trigger, | ||
836 | .pointer = lx_pcm_stream_pointer, | ||
837 | }; | ||
838 | |||
839 | static int __devinit lx_pcm_create(struct lx6464es *chip) | ||
840 | { | ||
841 | int err; | ||
842 | struct snd_pcm *pcm; | ||
843 | |||
844 | u32 size = 64 * /* channels */ | ||
845 | 3 * /* 24 bit samples */ | ||
846 | MAX_STREAM_BUFFER * /* periods */ | ||
847 | MICROBLAZE_IBL_MAX * /* frames per period */ | ||
848 | 2; /* duplex */ | ||
849 | |||
850 | size = PAGE_ALIGN(size); | ||
851 | |||
852 | /* hardcoded device name & channel count */ | ||
853 | err = snd_pcm_new(chip->card, (char *)card_name, 0, | ||
854 | 1, 1, &pcm); | ||
855 | |||
856 | pcm->private_data = chip; | ||
857 | |||
858 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &lx_ops_playback); | ||
859 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &lx_ops_capture); | ||
860 | |||
861 | pcm->info_flags = 0; | ||
862 | strcpy(pcm->name, card_name); | ||
863 | |||
864 | err = snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV, | ||
865 | snd_dma_pci_data(chip->pci), | ||
866 | size, size); | ||
867 | if (err < 0) | ||
868 | return err; | ||
869 | |||
870 | chip->pcm = pcm; | ||
871 | chip->capture_stream.is_capture = 1; | ||
872 | |||
873 | return 0; | ||
874 | } | ||
875 | |||
876 | static int lx_control_playback_info(struct snd_kcontrol *kcontrol, | ||
877 | struct snd_ctl_elem_info *uinfo) | ||
878 | { | ||
879 | uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; | ||
880 | uinfo->count = 1; | ||
881 | uinfo->value.integer.min = 0; | ||
882 | uinfo->value.integer.max = 1; | ||
883 | return 0; | ||
884 | } | ||
885 | |||
886 | static int lx_control_playback_get(struct snd_kcontrol *kcontrol, | ||
887 | struct snd_ctl_elem_value *ucontrol) | ||
888 | { | ||
889 | struct lx6464es *chip = snd_kcontrol_chip(kcontrol); | ||
890 | ucontrol->value.integer.value[0] = chip->playback_mute; | ||
891 | return 0; | ||
892 | } | ||
893 | |||
894 | static int lx_control_playback_put(struct snd_kcontrol *kcontrol, | ||
895 | struct snd_ctl_elem_value *ucontrol) | ||
896 | { | ||
897 | struct lx6464es *chip = snd_kcontrol_chip(kcontrol); | ||
898 | int changed = 0; | ||
899 | int current_value = chip->playback_mute; | ||
900 | |||
901 | if (current_value != ucontrol->value.integer.value[0]) { | ||
902 | lx_level_unmute(chip, 0, !current_value); | ||
903 | chip->playback_mute = !current_value; | ||
904 | changed = 1; | ||
905 | } | ||
906 | return changed; | ||
907 | } | ||
908 | |||
909 | static struct snd_kcontrol_new lx_control_playback_switch __devinitdata = { | ||
910 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
911 | .name = "PCM Playback Switch", | ||
912 | .index = 0, | ||
913 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | ||
914 | .private_value = 0, | ||
915 | .info = lx_control_playback_info, | ||
916 | .get = lx_control_playback_get, | ||
917 | .put = lx_control_playback_put | ||
918 | }; | ||
919 | |||
920 | |||
921 | |||
922 | static void lx_proc_levels_read(struct snd_info_entry *entry, | ||
923 | struct snd_info_buffer *buffer) | ||
924 | { | ||
925 | u32 levels[64]; | ||
926 | int err; | ||
927 | int i, j; | ||
928 | struct lx6464es *chip = entry->private_data; | ||
929 | |||
930 | snd_iprintf(buffer, "capture levels:\n"); | ||
931 | err = lx_level_peaks(chip, 1, 64, levels); | ||
932 | if (err < 0) | ||
933 | return; | ||
934 | |||
935 | for (i = 0; i != 8; ++i) { | ||
936 | for (j = 0; j != 8; ++j) | ||
937 | snd_iprintf(buffer, "%08x ", levels[i*8+j]); | ||
938 | snd_iprintf(buffer, "\n"); | ||
939 | } | ||
940 | |||
941 | snd_iprintf(buffer, "\nplayback levels:\n"); | ||
942 | |||
943 | err = lx_level_peaks(chip, 0, 64, levels); | ||
944 | if (err < 0) | ||
945 | return; | ||
946 | |||
947 | for (i = 0; i != 8; ++i) { | ||
948 | for (j = 0; j != 8; ++j) | ||
949 | snd_iprintf(buffer, "%08x ", levels[i*8+j]); | ||
950 | snd_iprintf(buffer, "\n"); | ||
951 | } | ||
952 | |||
953 | snd_iprintf(buffer, "\n"); | ||
954 | } | ||
955 | |||
956 | static int __devinit lx_proc_create(struct snd_card *card, struct lx6464es *chip) | ||
957 | { | ||
958 | struct snd_info_entry *entry; | ||
959 | int err = snd_card_proc_new(card, "levels", &entry); | ||
960 | if (err < 0) | ||
961 | return err; | ||
962 | |||
963 | snd_info_set_text_ops(entry, chip, lx_proc_levels_read); | ||
964 | return 0; | ||
965 | } | ||
966 | |||
967 | |||
968 | static int __devinit snd_lx6464es_create(struct snd_card *card, | ||
969 | struct pci_dev *pci, | ||
970 | struct lx6464es **rchip) | ||
971 | { | ||
972 | struct lx6464es *chip; | ||
973 | int err; | ||
974 | |||
975 | static struct snd_device_ops ops = { | ||
976 | .dev_free = snd_lx6464es_dev_free, | ||
977 | }; | ||
978 | |||
979 | snd_printdd("->snd_lx6464es_create\n"); | ||
980 | |||
981 | *rchip = NULL; | ||
982 | |||
983 | /* enable PCI device */ | ||
984 | err = pci_enable_device(pci); | ||
985 | if (err < 0) | ||
986 | return err; | ||
987 | |||
988 | pci_set_master(pci); | ||
989 | |||
990 | /* check if we can restrict PCI DMA transfers to 32 bits */ | ||
991 | err = pci_set_dma_mask(pci, DMA_32BIT_MASK); | ||
992 | if (err < 0) { | ||
993 | snd_printk(KERN_ERR "architecture does not support " | ||
994 | "32bit PCI busmaster DMA\n"); | ||
995 | pci_disable_device(pci); | ||
996 | return -ENXIO; | ||
997 | } | ||
998 | |||
999 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | ||
1000 | if (chip == NULL) { | ||
1001 | err = -ENOMEM; | ||
1002 | goto alloc_failed; | ||
1003 | } | ||
1004 | |||
1005 | chip->card = card; | ||
1006 | chip->pci = pci; | ||
1007 | chip->irq = -1; | ||
1008 | |||
1009 | /* initialize synchronization structs */ | ||
1010 | spin_lock_init(&chip->lock); | ||
1011 | spin_lock_init(&chip->msg_lock); | ||
1012 | mutex_init(&chip->setup_mutex); | ||
1013 | tasklet_init(&chip->trigger_tasklet, lx_trigger_tasklet, | ||
1014 | (unsigned long)chip); | ||
1015 | tasklet_init(&chip->tasklet_capture, lx_tasklet_capture, | ||
1016 | (unsigned long)chip); | ||
1017 | tasklet_init(&chip->tasklet_playback, lx_tasklet_playback, | ||
1018 | (unsigned long)chip); | ||
1019 | |||
1020 | /* request resources */ | ||
1021 | err = pci_request_regions(pci, card_name); | ||
1022 | if (err < 0) | ||
1023 | goto request_regions_failed; | ||
1024 | |||
1025 | /* plx port */ | ||
1026 | chip->port_plx = pci_resource_start(pci, 1); | ||
1027 | chip->port_plx_remapped = ioport_map(chip->port_plx, | ||
1028 | pci_resource_len(pci, 1)); | ||
1029 | |||
1030 | /* dsp port */ | ||
1031 | chip->port_dsp_bar = pci_ioremap_bar(pci, 2); | ||
1032 | |||
1033 | err = request_irq(pci->irq, lx_interrupt, IRQF_SHARED, | ||
1034 | card_name, chip); | ||
1035 | if (err) { | ||
1036 | snd_printk(KERN_ERR LXP "unable to grab IRQ %d\n", pci->irq); | ||
1037 | goto request_irq_failed; | ||
1038 | } | ||
1039 | chip->irq = pci->irq; | ||
1040 | |||
1041 | err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops); | ||
1042 | if (err < 0) | ||
1043 | goto device_new_failed; | ||
1044 | |||
1045 | err = lx_init_dsp(chip); | ||
1046 | if (err < 0) { | ||
1047 | snd_printk(KERN_ERR LXP "error during DSP initialization\n"); | ||
1048 | return err; | ||
1049 | } | ||
1050 | |||
1051 | err = lx_pcm_create(chip); | ||
1052 | if (err < 0) | ||
1053 | return err; | ||
1054 | |||
1055 | err = lx_proc_create(card, chip); | ||
1056 | if (err < 0) | ||
1057 | return err; | ||
1058 | |||
1059 | err = snd_ctl_add(card, snd_ctl_new1(&lx_control_playback_switch, | ||
1060 | chip)); | ||
1061 | if (err < 0) | ||
1062 | return err; | ||
1063 | |||
1064 | snd_card_set_dev(card, &pci->dev); | ||
1065 | |||
1066 | *rchip = chip; | ||
1067 | return 0; | ||
1068 | |||
1069 | device_new_failed: | ||
1070 | free_irq(pci->irq, chip); | ||
1071 | |||
1072 | request_irq_failed: | ||
1073 | pci_release_regions(pci); | ||
1074 | |||
1075 | request_regions_failed: | ||
1076 | kfree(chip); | ||
1077 | |||
1078 | alloc_failed: | ||
1079 | pci_disable_device(pci); | ||
1080 | |||
1081 | return err; | ||
1082 | } | ||
1083 | |||
1084 | static int __devinit snd_lx6464es_probe(struct pci_dev *pci, | ||
1085 | const struct pci_device_id *pci_id) | ||
1086 | { | ||
1087 | static int dev; | ||
1088 | struct snd_card *card; | ||
1089 | struct lx6464es *chip; | ||
1090 | int err; | ||
1091 | |||
1092 | snd_printdd("->snd_lx6464es_probe\n"); | ||
1093 | |||
1094 | if (dev >= SNDRV_CARDS) | ||
1095 | return -ENODEV; | ||
1096 | if (!enable[dev]) { | ||
1097 | dev++; | ||
1098 | return -ENOENT; | ||
1099 | } | ||
1100 | |||
1101 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | ||
1102 | if (err < 0) | ||
1103 | return err; | ||
1104 | |||
1105 | err = snd_lx6464es_create(card, pci, &chip); | ||
1106 | if (err < 0) { | ||
1107 | snd_printk(KERN_ERR LXP "error during snd_lx6464es_create\n"); | ||
1108 | goto out_free; | ||
1109 | } | ||
1110 | |||
1111 | strcpy(card->driver, "lx6464es"); | ||
1112 | strcpy(card->shortname, "Digigram LX6464ES"); | ||
1113 | sprintf(card->longname, "%s at 0x%lx, 0x%p, irq %i", | ||
1114 | card->shortname, chip->port_plx, | ||
1115 | chip->port_dsp_bar, chip->irq); | ||
1116 | |||
1117 | err = snd_card_register(card); | ||
1118 | if (err < 0) | ||
1119 | goto out_free; | ||
1120 | |||
1121 | snd_printdd(LXP "initialization successful\n"); | ||
1122 | pci_set_drvdata(pci, card); | ||
1123 | dev++; | ||
1124 | return 0; | ||
1125 | |||
1126 | out_free: | ||
1127 | snd_card_free(card); | ||
1128 | return err; | ||
1129 | |||
1130 | } | ||
1131 | |||
1132 | static void __devexit snd_lx6464es_remove(struct pci_dev *pci) | ||
1133 | { | ||
1134 | snd_card_free(pci_get_drvdata(pci)); | ||
1135 | pci_set_drvdata(pci, NULL); | ||
1136 | } | ||
1137 | |||
1138 | |||
1139 | static struct pci_driver driver = { | ||
1140 | .name = "Digigram LX6464ES", | ||
1141 | .id_table = snd_lx6464es_ids, | ||
1142 | .probe = snd_lx6464es_probe, | ||
1143 | .remove = __devexit_p(snd_lx6464es_remove), | ||
1144 | }; | ||
1145 | |||
1146 | |||
1147 | /* module initialization */ | ||
1148 | static int __init mod_init(void) | ||
1149 | { | ||
1150 | return pci_register_driver(&driver); | ||
1151 | } | ||
1152 | |||
1153 | static void __exit mod_exit(void) | ||
1154 | { | ||
1155 | pci_unregister_driver(&driver); | ||
1156 | } | ||
1157 | |||
1158 | module_init(mod_init); | ||
1159 | module_exit(mod_exit); | ||
diff --git a/sound/pci/lx6464es/lx6464es.h b/sound/pci/lx6464es/lx6464es.h new file mode 100644 index 000000000000..012c010c8c89 --- /dev/null +++ b/sound/pci/lx6464es/lx6464es.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* -*- linux-c -*- * | ||
2 | * | ||
3 | * ALSA driver for the digigram lx6464es interface | ||
4 | * | ||
5 | * Copyright (c) 2009 Tim Blechmann <tim@klingt.org> | ||
6 | * | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, write to | ||
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
21 | * Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef LX6464ES_H | ||
26 | #define LX6464ES_H | ||
27 | |||
28 | #include <linux/spinlock.h> | ||
29 | #include <asm/atomic.h> | ||
30 | |||
31 | #include <sound/core.h> | ||
32 | #include <sound/pcm.h> | ||
33 | |||
34 | #include "lx_core.h" | ||
35 | |||
36 | #define LXP "LX6464ES: " | ||
37 | |||
38 | enum { | ||
39 | ES_cmd_free = 0, /* no command executing */ | ||
40 | ES_cmd_processing = 1, /* execution of a read/write command */ | ||
41 | ES_read_pending = 2, /* a asynchron read command is pending */ | ||
42 | ES_read_finishing = 3, /* a read command has finished waiting (set by | ||
43 | * Interrupt or CancelIrp) */ | ||
44 | }; | ||
45 | |||
46 | enum lx_stream_status { | ||
47 | LX_STREAM_STATUS_FREE, | ||
48 | /* LX_STREAM_STATUS_OPEN, */ | ||
49 | LX_STREAM_STATUS_SCHEDULE_RUN, | ||
50 | /* LX_STREAM_STATUS_STARTED, */ | ||
51 | LX_STREAM_STATUS_RUNNING, | ||
52 | LX_STREAM_STATUS_SCHEDULE_STOP, | ||
53 | /* LX_STREAM_STATUS_STOPPED, */ | ||
54 | /* LX_STREAM_STATUS_PAUSED */ | ||
55 | }; | ||
56 | |||
57 | |||
58 | struct lx_stream { | ||
59 | struct snd_pcm_substream *stream; | ||
60 | snd_pcm_uframes_t frame_pos; | ||
61 | enum lx_stream_status status; /* free, open, running, draining | ||
62 | * pause */ | ||
63 | int is_capture:1; | ||
64 | }; | ||
65 | |||
66 | |||
67 | struct lx6464es { | ||
68 | struct snd_card *card; | ||
69 | struct pci_dev *pci; | ||
70 | int irq; | ||
71 | |||
72 | spinlock_t lock; /* interrupt spinlock */ | ||
73 | struct mutex setup_mutex; /* mutex used in hw_params, open | ||
74 | * and close */ | ||
75 | |||
76 | struct tasklet_struct trigger_tasklet; /* trigger tasklet */ | ||
77 | struct tasklet_struct tasklet_capture; | ||
78 | struct tasklet_struct tasklet_playback; | ||
79 | |||
80 | /* ports */ | ||
81 | unsigned long port_plx; /* io port (size=256) */ | ||
82 | void __iomem *port_plx_remapped; /* remapped plx port */ | ||
83 | void __iomem *port_dsp_bar; /* memory port (32-bit, | ||
84 | * non-prefetchable, | ||
85 | * size=8K) */ | ||
86 | |||
87 | /* messaging */ | ||
88 | spinlock_t msg_lock; /* message spinlock */ | ||
89 | atomic_t send_message_locked; | ||
90 | struct lx_rmh rmh; | ||
91 | |||
92 | /* configuration */ | ||
93 | uint freq_ratio : 2; | ||
94 | uint playback_mute : 1; | ||
95 | uint hardware_running[2]; | ||
96 | u32 board_sample_rate; /* sample rate read from | ||
97 | * board */ | ||
98 | u32 sample_rate; /* our sample rate */ | ||
99 | u16 pcm_granularity; /* board blocksize */ | ||
100 | |||
101 | /* dma */ | ||
102 | struct snd_dma_buffer capture_dma_buf; | ||
103 | struct snd_dma_buffer playback_dma_buf; | ||
104 | |||
105 | /* pcm */ | ||
106 | struct snd_pcm *pcm; | ||
107 | |||
108 | /* streams */ | ||
109 | struct lx_stream capture_stream; | ||
110 | struct lx_stream playback_stream; | ||
111 | }; | ||
112 | |||
113 | |||
114 | #endif /* LX6464ES_H */ | ||
diff --git a/sound/pci/lx6464es/lx_core.c b/sound/pci/lx6464es/lx_core.c new file mode 100644 index 000000000000..5812780d6e89 --- /dev/null +++ b/sound/pci/lx6464es/lx_core.c | |||
@@ -0,0 +1,1444 @@ | |||
1 | /* -*- linux-c -*- * | ||
2 | * | ||
3 | * ALSA driver for the digigram lx6464es interface | ||
4 | * low-level interface | ||
5 | * | ||
6 | * Copyright (c) 2009 Tim Blechmann <tim@klingt.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, write to | ||
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
21 | * Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | /* #define RMH_DEBUG 1 */ | ||
26 | |||
27 | #include <linux/module.h> | ||
28 | #include <linux/pci.h> | ||
29 | #include <linux/delay.h> | ||
30 | |||
31 | #include "lx6464es.h" | ||
32 | #include "lx_core.h" | ||
33 | |||
34 | /* low-level register access */ | ||
35 | |||
36 | static const unsigned long dsp_port_offsets[] = { | ||
37 | 0, | ||
38 | 0x400, | ||
39 | 0x401, | ||
40 | 0x402, | ||
41 | 0x403, | ||
42 | 0x404, | ||
43 | 0x405, | ||
44 | 0x406, | ||
45 | 0x407, | ||
46 | 0x408, | ||
47 | 0x409, | ||
48 | 0x40a, | ||
49 | 0x40b, | ||
50 | 0x40c, | ||
51 | |||
52 | 0x410, | ||
53 | 0x411, | ||
54 | 0x412, | ||
55 | 0x413, | ||
56 | 0x414, | ||
57 | 0x415, | ||
58 | 0x416, | ||
59 | |||
60 | 0x420, | ||
61 | 0x430, | ||
62 | 0x431, | ||
63 | 0x432, | ||
64 | 0x433, | ||
65 | 0x434, | ||
66 | 0x440 | ||
67 | }; | ||
68 | |||
69 | static void __iomem *lx_dsp_register(struct lx6464es *chip, int port) | ||
70 | { | ||
71 | void __iomem *base_address = chip->port_dsp_bar; | ||
72 | return base_address + dsp_port_offsets[port]*4; | ||
73 | } | ||
74 | |||
75 | unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port) | ||
76 | { | ||
77 | void __iomem *address = lx_dsp_register(chip, port); | ||
78 | return ioread32(address); | ||
79 | } | ||
80 | |||
81 | void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len) | ||
82 | { | ||
83 | void __iomem *address = lx_dsp_register(chip, port); | ||
84 | memcpy_fromio(data, address, len*sizeof(u32)); | ||
85 | } | ||
86 | |||
87 | |||
88 | void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data) | ||
89 | { | ||
90 | void __iomem *address = lx_dsp_register(chip, port); | ||
91 | iowrite32(data, address); | ||
92 | } | ||
93 | |||
94 | void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, | ||
95 | u32 len) | ||
96 | { | ||
97 | void __iomem *address = lx_dsp_register(chip, port); | ||
98 | memcpy_toio(address, data, len*sizeof(u32)); | ||
99 | } | ||
100 | |||
101 | |||
102 | static const unsigned long plx_port_offsets[] = { | ||
103 | 0x04, | ||
104 | 0x40, | ||
105 | 0x44, | ||
106 | 0x48, | ||
107 | 0x4c, | ||
108 | 0x50, | ||
109 | 0x54, | ||
110 | 0x58, | ||
111 | 0x5c, | ||
112 | 0x64, | ||
113 | 0x68, | ||
114 | 0x6C | ||
115 | }; | ||
116 | |||
117 | static void __iomem *lx_plx_register(struct lx6464es *chip, int port) | ||
118 | { | ||
119 | void __iomem *base_address = chip->port_plx_remapped; | ||
120 | return base_address + plx_port_offsets[port]; | ||
121 | } | ||
122 | |||
123 | unsigned long lx_plx_reg_read(struct lx6464es *chip, int port) | ||
124 | { | ||
125 | void __iomem *address = lx_plx_register(chip, port); | ||
126 | return ioread32(address); | ||
127 | } | ||
128 | |||
129 | void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data) | ||
130 | { | ||
131 | void __iomem *address = lx_plx_register(chip, port); | ||
132 | iowrite32(data, address); | ||
133 | } | ||
134 | |||
135 | u32 lx_plx_mbox_read(struct lx6464es *chip, int mbox_nr) | ||
136 | { | ||
137 | int index; | ||
138 | |||
139 | switch (mbox_nr) { | ||
140 | case 1: | ||
141 | index = ePLX_MBOX1; break; | ||
142 | case 2: | ||
143 | index = ePLX_MBOX2; break; | ||
144 | case 3: | ||
145 | index = ePLX_MBOX3; break; | ||
146 | case 4: | ||
147 | index = ePLX_MBOX4; break; | ||
148 | case 5: | ||
149 | index = ePLX_MBOX5; break; | ||
150 | case 6: | ||
151 | index = ePLX_MBOX6; break; | ||
152 | case 7: | ||
153 | index = ePLX_MBOX7; break; | ||
154 | case 0: /* reserved for HF flags */ | ||
155 | snd_BUG(); | ||
156 | default: | ||
157 | return 0xdeadbeef; | ||
158 | } | ||
159 | |||
160 | return lx_plx_reg_read(chip, index); | ||
161 | } | ||
162 | |||
163 | int lx_plx_mbox_write(struct lx6464es *chip, int mbox_nr, u32 value) | ||
164 | { | ||
165 | int index = -1; | ||
166 | |||
167 | switch (mbox_nr) { | ||
168 | case 1: | ||
169 | index = ePLX_MBOX1; break; | ||
170 | case 3: | ||
171 | index = ePLX_MBOX3; break; | ||
172 | case 4: | ||
173 | index = ePLX_MBOX4; break; | ||
174 | case 5: | ||
175 | index = ePLX_MBOX5; break; | ||
176 | case 6: | ||
177 | index = ePLX_MBOX6; break; | ||
178 | case 7: | ||
179 | index = ePLX_MBOX7; break; | ||
180 | case 0: /* reserved for HF flags */ | ||
181 | case 2: /* reserved for Pipe States | ||
182 | * the DSP keeps an image of it */ | ||
183 | snd_BUG(); | ||
184 | return -EBADRQC; | ||
185 | } | ||
186 | |||
187 | lx_plx_reg_write(chip, index, value); | ||
188 | return 0; | ||
189 | } | ||
190 | |||
191 | |||
192 | /* rmh */ | ||
193 | |||
194 | #ifdef CONFIG_SND_DEBUG | ||
195 | #define CMD_NAME(a) a | ||
196 | #else | ||
197 | #define CMD_NAME(a) NULL | ||
198 | #endif | ||
199 | |||
200 | #define Reg_CSM_MR 0x00000002 | ||
201 | #define Reg_CSM_MC 0x00000001 | ||
202 | |||
203 | struct dsp_cmd_info { | ||
204 | u32 dcCodeOp; /* Op Code of the command (usually 1st 24-bits | ||
205 | * word).*/ | ||
206 | u16 dcCmdLength; /* Command length in words of 24 bits.*/ | ||
207 | u16 dcStatusType; /* Status type: 0 for fixed length, 1 for | ||
208 | * random. */ | ||
209 | u16 dcStatusLength; /* Status length (if fixed).*/ | ||
210 | char *dcOpName; | ||
211 | }; | ||
212 | |||
213 | /* | ||
214 | Initialization and control data for the Microblaze interface | ||
215 | - OpCode: | ||
216 | the opcode field of the command set at the proper offset | ||
217 | - CmdLength | ||
218 | the number of command words | ||
219 | - StatusType | ||
220 | offset in the status registers: 0 means that the return value may be | ||
221 | different from 0, and must be read | ||
222 | - StatusLength | ||
223 | the number of status words (in addition to the return value) | ||
224 | */ | ||
225 | |||
226 | static struct dsp_cmd_info dsp_commands[] = | ||
227 | { | ||
228 | { (CMD_00_INFO_DEBUG << OPCODE_OFFSET) , 1 /*custom*/ | ||
229 | , 1 , 0 /**/ , CMD_NAME("INFO_DEBUG") }, | ||
230 | { (CMD_01_GET_SYS_CFG << OPCODE_OFFSET) , 1 /**/ | ||
231 | , 1 , 2 /**/ , CMD_NAME("GET_SYS_CFG") }, | ||
232 | { (CMD_02_SET_GRANULARITY << OPCODE_OFFSET) , 1 /**/ | ||
233 | , 1 , 0 /**/ , CMD_NAME("SET_GRANULARITY") }, | ||
234 | { (CMD_03_SET_TIMER_IRQ << OPCODE_OFFSET) , 1 /**/ | ||
235 | , 1 , 0 /**/ , CMD_NAME("SET_TIMER_IRQ") }, | ||
236 | { (CMD_04_GET_EVENT << OPCODE_OFFSET) , 1 /**/ | ||
237 | , 1 , 0 /*up to 10*/ , CMD_NAME("GET_EVENT") }, | ||
238 | { (CMD_05_GET_PIPES << OPCODE_OFFSET) , 1 /**/ | ||
239 | , 1 , 2 /*up to 4*/ , CMD_NAME("GET_PIPES") }, | ||
240 | { (CMD_06_ALLOCATE_PIPE << OPCODE_OFFSET) , 1 /**/ | ||
241 | , 0 , 0 /**/ , CMD_NAME("ALLOCATE_PIPE") }, | ||
242 | { (CMD_07_RELEASE_PIPE << OPCODE_OFFSET) , 1 /**/ | ||
243 | , 0 , 0 /**/ , CMD_NAME("RELEASE_PIPE") }, | ||
244 | { (CMD_08_ASK_BUFFERS << OPCODE_OFFSET) , 1 /**/ | ||
245 | , 1 , MAX_STREAM_BUFFER , CMD_NAME("ASK_BUFFERS") }, | ||
246 | { (CMD_09_STOP_PIPE << OPCODE_OFFSET) , 1 /**/ | ||
247 | , 0 , 0 /*up to 2*/ , CMD_NAME("STOP_PIPE") }, | ||
248 | { (CMD_0A_GET_PIPE_SPL_COUNT << OPCODE_OFFSET) , 1 /**/ | ||
249 | , 1 , 1 /*up to 2*/ , CMD_NAME("GET_PIPE_SPL_COUNT") }, | ||
250 | { (CMD_0B_TOGGLE_PIPE_STATE << OPCODE_OFFSET) , 1 /*up to 5*/ | ||
251 | , 1 , 0 /**/ , CMD_NAME("TOGGLE_PIPE_STATE") }, | ||
252 | { (CMD_0C_DEF_STREAM << OPCODE_OFFSET) , 1 /*up to 4*/ | ||
253 | , 1 , 0 /**/ , CMD_NAME("DEF_STREAM") }, | ||
254 | { (CMD_0D_SET_MUTE << OPCODE_OFFSET) , 3 /**/ | ||
255 | , 1 , 0 /**/ , CMD_NAME("SET_MUTE") }, | ||
256 | { (CMD_0E_GET_STREAM_SPL_COUNT << OPCODE_OFFSET) , 1/**/ | ||
257 | , 1 , 2 /**/ , CMD_NAME("GET_STREAM_SPL_COUNT") }, | ||
258 | { (CMD_0F_UPDATE_BUFFER << OPCODE_OFFSET) , 3 /*up to 4*/ | ||
259 | , 0 , 1 /**/ , CMD_NAME("UPDATE_BUFFER") }, | ||
260 | { (CMD_10_GET_BUFFER << OPCODE_OFFSET) , 1 /**/ | ||
261 | , 1 , 4 /**/ , CMD_NAME("GET_BUFFER") }, | ||
262 | { (CMD_11_CANCEL_BUFFER << OPCODE_OFFSET) , 1 /**/ | ||
263 | , 1 , 1 /*up to 4*/ , CMD_NAME("CANCEL_BUFFER") }, | ||
264 | { (CMD_12_GET_PEAK << OPCODE_OFFSET) , 1 /**/ | ||
265 | , 1 , 1 /**/ , CMD_NAME("GET_PEAK") }, | ||
266 | { (CMD_13_SET_STREAM_STATE << OPCODE_OFFSET) , 1 /**/ | ||
267 | , 1 , 0 /**/ , CMD_NAME("SET_STREAM_STATE") }, | ||
268 | }; | ||
269 | |||
270 | static void lx_message_init(struct lx_rmh *rmh, enum cmd_mb_opcodes cmd) | ||
271 | { | ||
272 | snd_BUG_ON(cmd >= CMD_14_INVALID); | ||
273 | |||
274 | rmh->cmd[0] = dsp_commands[cmd].dcCodeOp; | ||
275 | rmh->cmd_len = dsp_commands[cmd].dcCmdLength; | ||
276 | rmh->stat_len = dsp_commands[cmd].dcStatusLength; | ||
277 | rmh->dsp_stat = dsp_commands[cmd].dcStatusType; | ||
278 | rmh->cmd_idx = cmd; | ||
279 | memset(&rmh->cmd[1], 0, (REG_CRM_NUMBER - 1) * sizeof(u32)); | ||
280 | |||
281 | #ifdef CONFIG_SND_DEBUG | ||
282 | memset(rmh->stat, 0, REG_CRM_NUMBER * sizeof(u32)); | ||
283 | #endif | ||
284 | #ifdef RMH_DEBUG | ||
285 | rmh->cmd_idx = cmd; | ||
286 | #endif | ||
287 | } | ||
288 | |||
289 | #ifdef RMH_DEBUG | ||
290 | #define LXRMH "lx6464es rmh: " | ||
291 | static void lx_message_dump(struct lx_rmh *rmh) | ||
292 | { | ||
293 | u8 idx = rmh->cmd_idx; | ||
294 | int i; | ||
295 | |||
296 | snd_printk(LXRMH "command %s\n", dsp_commands[idx].dcOpName); | ||
297 | |||
298 | for (i = 0; i != rmh->cmd_len; ++i) | ||
299 | snd_printk(LXRMH "\tcmd[%d] %08x\n", i, rmh->cmd[i]); | ||
300 | |||
301 | for (i = 0; i != rmh->stat_len; ++i) | ||
302 | snd_printk(LXRMH "\tstat[%d]: %08x\n", i, rmh->stat[i]); | ||
303 | snd_printk("\n"); | ||
304 | } | ||
305 | #else | ||
306 | static inline void lx_message_dump(struct lx_rmh *rmh) | ||
307 | {} | ||
308 | #endif | ||
309 | |||
310 | |||
311 | |||
312 | /* sleep 500 - 100 = 400 times 100us -> the timeout is >= 40 ms */ | ||
313 | #define XILINX_TIMEOUT_MS 40 | ||
314 | #define XILINX_POLL_NO_SLEEP 100 | ||
315 | #define XILINX_POLL_ITERATIONS 150 | ||
316 | |||
317 | #if 0 /* not used now */ | ||
318 | static int lx_message_send(struct lx6464es *chip, struct lx_rmh *rmh) | ||
319 | { | ||
320 | u32 reg = ED_DSP_TIMED_OUT; | ||
321 | int dwloop; | ||
322 | int answer_received; | ||
323 | |||
324 | if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { | ||
325 | snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); | ||
326 | return -EBUSY; | ||
327 | } | ||
328 | |||
329 | /* write command */ | ||
330 | lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len); | ||
331 | |||
332 | snd_BUG_ON(atomic_read(&chip->send_message_locked) != 0); | ||
333 | atomic_set(&chip->send_message_locked, 1); | ||
334 | |||
335 | /* MicoBlaze gogogo */ | ||
336 | lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC); | ||
337 | |||
338 | /* wait for interrupt to answer */ | ||
339 | for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS; ++dwloop) { | ||
340 | answer_received = atomic_read(&chip->send_message_locked); | ||
341 | if (answer_received == 0) | ||
342 | break; | ||
343 | msleep(1); | ||
344 | } | ||
345 | |||
346 | if (answer_received == 0) { | ||
347 | /* in Debug mode verify Reg_CSM_MR */ | ||
348 | snd_BUG_ON(!(lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR)); | ||
349 | |||
350 | /* command finished, read status */ | ||
351 | if (rmh->dsp_stat == 0) | ||
352 | reg = lx_dsp_reg_read(chip, eReg_CRM1); | ||
353 | else | ||
354 | reg = 0; | ||
355 | } else { | ||
356 | int i; | ||
357 | snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! " | ||
358 | "Interrupts disabled?\n"); | ||
359 | |||
360 | /* attente bit Reg_CSM_MR */ | ||
361 | for (i = 0; i != XILINX_POLL_ITERATIONS; i++) { | ||
362 | if ((lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR)) { | ||
363 | if (rmh->dsp_stat == 0) | ||
364 | reg = lx_dsp_reg_read(chip, eReg_CRM1); | ||
365 | else | ||
366 | reg = 0; | ||
367 | goto polling_successful; | ||
368 | } | ||
369 | |||
370 | if (i > XILINX_POLL_NO_SLEEP) | ||
371 | msleep(1); | ||
372 | } | ||
373 | snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send! " | ||
374 | "polling failed\n"); | ||
375 | |||
376 | polling_successful: | ||
377 | atomic_set(&chip->send_message_locked, 0); | ||
378 | } | ||
379 | |||
380 | if ((reg & ERROR_VALUE) == 0) { | ||
381 | /* read response */ | ||
382 | if (rmh->stat_len) { | ||
383 | snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1)); | ||
384 | |||
385 | lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, | ||
386 | rmh->stat_len); | ||
387 | } | ||
388 | } else | ||
389 | snd_printk(KERN_WARNING LXP "lx_message_send: error_value %x\n", | ||
390 | reg); | ||
391 | |||
392 | /* clear Reg_CSM_MR */ | ||
393 | lx_dsp_reg_write(chip, eReg_CSM, 0); | ||
394 | |||
395 | switch (reg) { | ||
396 | case ED_DSP_TIMED_OUT: | ||
397 | snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); | ||
398 | return -ETIMEDOUT; | ||
399 | |||
400 | case ED_DSP_CRASHED: | ||
401 | snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); | ||
402 | return -EAGAIN; | ||
403 | } | ||
404 | |||
405 | lx_message_dump(rmh); | ||
406 | return 0; | ||
407 | } | ||
408 | #endif /* not used now */ | ||
409 | |||
410 | static int lx_message_send_atomic(struct lx6464es *chip, struct lx_rmh *rmh) | ||
411 | { | ||
412 | u32 reg = ED_DSP_TIMED_OUT; | ||
413 | int dwloop; | ||
414 | |||
415 | if (lx_dsp_reg_read(chip, eReg_CSM) & (Reg_CSM_MC | Reg_CSM_MR)) { | ||
416 | snd_printk(KERN_ERR LXP "PIOSendMessage eReg_CSM %x\n", reg); | ||
417 | return -EBUSY; | ||
418 | } | ||
419 | |||
420 | /* write command */ | ||
421 | lx_dsp_reg_writebuf(chip, eReg_CRM1, rmh->cmd, rmh->cmd_len); | ||
422 | |||
423 | /* MicoBlaze gogogo */ | ||
424 | lx_dsp_reg_write(chip, eReg_CSM, Reg_CSM_MC); | ||
425 | |||
426 | /* wait for interrupt to answer */ | ||
427 | for (dwloop = 0; dwloop != XILINX_TIMEOUT_MS * 1000; ++dwloop) { | ||
428 | if (lx_dsp_reg_read(chip, eReg_CSM) & Reg_CSM_MR) { | ||
429 | if (rmh->dsp_stat == 0) | ||
430 | reg = lx_dsp_reg_read(chip, eReg_CRM1); | ||
431 | else | ||
432 | reg = 0; | ||
433 | goto polling_successful; | ||
434 | } else | ||
435 | udelay(1); | ||
436 | } | ||
437 | snd_printk(KERN_WARNING LXP "TIMEOUT lx_message_send_atomic! " | ||
438 | "polling failed\n"); | ||
439 | |||
440 | polling_successful: | ||
441 | if ((reg & ERROR_VALUE) == 0) { | ||
442 | /* read response */ | ||
443 | if (rmh->stat_len) { | ||
444 | snd_BUG_ON(rmh->stat_len >= (REG_CRM_NUMBER-1)); | ||
445 | lx_dsp_reg_readbuf(chip, eReg_CRM2, rmh->stat, | ||
446 | rmh->stat_len); | ||
447 | } | ||
448 | } else | ||
449 | snd_printk(LXP "rmh error: %08x\n", reg); | ||
450 | |||
451 | /* clear Reg_CSM_MR */ | ||
452 | lx_dsp_reg_write(chip, eReg_CSM, 0); | ||
453 | |||
454 | switch (reg) { | ||
455 | case ED_DSP_TIMED_OUT: | ||
456 | snd_printk(KERN_WARNING LXP "lx_message_send: dsp timeout\n"); | ||
457 | return -ETIMEDOUT; | ||
458 | |||
459 | case ED_DSP_CRASHED: | ||
460 | snd_printk(KERN_WARNING LXP "lx_message_send: dsp crashed\n"); | ||
461 | return -EAGAIN; | ||
462 | } | ||
463 | |||
464 | lx_message_dump(rmh); | ||
465 | |||
466 | return reg; | ||
467 | } | ||
468 | |||
469 | |||
470 | /* low-level dsp access */ | ||
471 | int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version) | ||
472 | { | ||
473 | u16 ret; | ||
474 | unsigned long flags; | ||
475 | |||
476 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
477 | |||
478 | lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); | ||
479 | ret = lx_message_send_atomic(chip, &chip->rmh); | ||
480 | |||
481 | *rdsp_version = chip->rmh.stat[1]; | ||
482 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
483 | return ret; | ||
484 | } | ||
485 | |||
486 | int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq) | ||
487 | { | ||
488 | u16 ret = 0; | ||
489 | unsigned long flags; | ||
490 | u32 freq_raw = 0; | ||
491 | u32 freq = 0; | ||
492 | u32 frequency = 0; | ||
493 | |||
494 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
495 | |||
496 | lx_message_init(&chip->rmh, CMD_01_GET_SYS_CFG); | ||
497 | ret = lx_message_send_atomic(chip, &chip->rmh); | ||
498 | |||
499 | if (ret == 0) { | ||
500 | freq_raw = chip->rmh.stat[0] >> FREQ_FIELD_OFFSET; | ||
501 | freq = freq_raw & XES_FREQ_COUNT8_MASK; | ||
502 | |||
503 | if ((freq < XES_FREQ_COUNT8_48_MAX) || | ||
504 | (freq > XES_FREQ_COUNT8_44_MIN)) | ||
505 | frequency = 0; /* unknown */ | ||
506 | else if (freq >= XES_FREQ_COUNT8_44_MAX) | ||
507 | frequency = 44100; | ||
508 | else | ||
509 | frequency = 48000; | ||
510 | } | ||
511 | |||
512 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
513 | |||
514 | *rfreq = frequency * chip->freq_ratio; | ||
515 | |||
516 | return ret; | ||
517 | } | ||
518 | |||
519 | int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address) | ||
520 | { | ||
521 | u32 macmsb, maclsb; | ||
522 | |||
523 | macmsb = lx_dsp_reg_read(chip, eReg_ADMACESMSB) & 0x00FFFFFF; | ||
524 | maclsb = lx_dsp_reg_read(chip, eReg_ADMACESLSB) & 0x00FFFFFF; | ||
525 | |||
526 | /* todo: endianess handling */ | ||
527 | mac_address[5] = ((u8 *)(&maclsb))[0]; | ||
528 | mac_address[4] = ((u8 *)(&maclsb))[1]; | ||
529 | mac_address[3] = ((u8 *)(&maclsb))[2]; | ||
530 | mac_address[2] = ((u8 *)(&macmsb))[0]; | ||
531 | mac_address[1] = ((u8 *)(&macmsb))[1]; | ||
532 | mac_address[0] = ((u8 *)(&macmsb))[2]; | ||
533 | |||
534 | return 0; | ||
535 | } | ||
536 | |||
537 | |||
538 | int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran) | ||
539 | { | ||
540 | unsigned long flags; | ||
541 | int ret; | ||
542 | |||
543 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
544 | |||
545 | lx_message_init(&chip->rmh, CMD_02_SET_GRANULARITY); | ||
546 | chip->rmh.cmd[0] |= gran; | ||
547 | |||
548 | ret = lx_message_send_atomic(chip, &chip->rmh); | ||
549 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
550 | return ret; | ||
551 | } | ||
552 | |||
553 | int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data) | ||
554 | { | ||
555 | unsigned long flags; | ||
556 | int ret; | ||
557 | |||
558 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
559 | |||
560 | lx_message_init(&chip->rmh, CMD_04_GET_EVENT); | ||
561 | chip->rmh.stat_len = 9; /* we don't necessarily need the full length */ | ||
562 | |||
563 | ret = lx_message_send_atomic(chip, &chip->rmh); | ||
564 | |||
565 | if (!ret) | ||
566 | memcpy(data, chip->rmh.stat, chip->rmh.stat_len * sizeof(u32)); | ||
567 | |||
568 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
569 | return ret; | ||
570 | } | ||
571 | |||
572 | #define CSES_TIMEOUT 100 /* microseconds */ | ||
573 | #define CSES_CE 0x0001 | ||
574 | #define CSES_BROADCAST 0x0002 | ||
575 | #define CSES_UPDATE_LDSV 0x0004 | ||
576 | |||
577 | int lx_dsp_es_check_pipeline(struct lx6464es *chip) | ||
578 | { | ||
579 | int i; | ||
580 | |||
581 | for (i = 0; i != CSES_TIMEOUT; ++i) { | ||
582 | /* | ||
583 | * le bit CSES_UPDATE_LDSV est à1 dés que le macprog | ||
584 | * est pret. il re-passe à0 lorsque le premier read a | ||
585 | * été fait. pour l'instant on retire le test car ce bit | ||
586 | * passe a 1 environ 200 à400 ms aprés que le registre | ||
587 | * confES àété écrit (kick du xilinx ES). | ||
588 | * | ||
589 | * On ne teste que le bit CE. | ||
590 | * */ | ||
591 | |||
592 | u32 cses = lx_dsp_reg_read(chip, eReg_CSES); | ||
593 | |||
594 | if ((cses & CSES_CE) == 0) | ||
595 | return 0; | ||
596 | |||
597 | udelay(1); | ||
598 | } | ||
599 | |||
600 | return -ETIMEDOUT; | ||
601 | } | ||
602 | |||
603 | |||
604 | #define PIPE_INFO_TO_CMD(capture, pipe) \ | ||
605 | ((u32)((u32)(pipe) | ((capture) ? ID_IS_CAPTURE : 0L)) << ID_OFFSET) | ||
606 | |||
607 | |||
608 | |||
609 | /* low-level pipe handling */ | ||
610 | int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, | ||
611 | int channels) | ||
612 | { | ||
613 | int err; | ||
614 | unsigned long flags; | ||
615 | |||
616 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
617 | |||
618 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
619 | lx_message_init(&chip->rmh, CMD_06_ALLOCATE_PIPE); | ||
620 | |||
621 | chip->rmh.cmd[0] |= pipe_cmd; | ||
622 | chip->rmh.cmd[0] |= channels; | ||
623 | |||
624 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
625 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
626 | |||
627 | if (err != 0) | ||
628 | snd_printk(KERN_ERR "lx6464es: could not allocate pipe\n"); | ||
629 | |||
630 | return err; | ||
631 | } | ||
632 | |||
633 | int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture) | ||
634 | { | ||
635 | int err; | ||
636 | unsigned long flags; | ||
637 | |||
638 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
639 | |||
640 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
641 | lx_message_init(&chip->rmh, CMD_07_RELEASE_PIPE); | ||
642 | |||
643 | chip->rmh.cmd[0] |= pipe_cmd; | ||
644 | |||
645 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
646 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
647 | |||
648 | return err; | ||
649 | } | ||
650 | |||
651 | int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, | ||
652 | u32 *r_needed, u32 *r_freed, u32 *size_array) | ||
653 | { | ||
654 | int err; | ||
655 | unsigned long flags; | ||
656 | |||
657 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
658 | |||
659 | #ifdef CONFIG_SND_DEBUG | ||
660 | if (size_array) | ||
661 | memset(size_array, 0, sizeof(u32)*MAX_STREAM_BUFFER); | ||
662 | #endif | ||
663 | |||
664 | *r_needed = 0; | ||
665 | *r_freed = 0; | ||
666 | |||
667 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
668 | lx_message_init(&chip->rmh, CMD_08_ASK_BUFFERS); | ||
669 | |||
670 | chip->rmh.cmd[0] |= pipe_cmd; | ||
671 | |||
672 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
673 | |||
674 | if (!err) { | ||
675 | int i; | ||
676 | for (i = 0; i < MAX_STREAM_BUFFER; ++i) { | ||
677 | u32 stat = chip->rmh.stat[i]; | ||
678 | if (stat & (BF_EOB << BUFF_FLAGS_OFFSET)) { | ||
679 | /* finished */ | ||
680 | *r_freed += 1; | ||
681 | if (size_array) | ||
682 | size_array[i] = stat & MASK_DATA_SIZE; | ||
683 | } else if ((stat & (BF_VALID << BUFF_FLAGS_OFFSET)) | ||
684 | == 0) | ||
685 | /* free */ | ||
686 | *r_needed += 1; | ||
687 | } | ||
688 | |||
689 | #if 0 | ||
690 | snd_printdd(LXP "CMD_08_ASK_BUFFERS: needed %d, freed %d\n", | ||
691 | *r_needed, *r_freed); | ||
692 | for (i = 0; i < MAX_STREAM_BUFFER; ++i) { | ||
693 | for (i = 0; i != chip->rmh.stat_len; ++i) | ||
694 | snd_printdd(" stat[%d]: %x, %x\n", i, | ||
695 | chip->rmh.stat[i], | ||
696 | chip->rmh.stat[i] & MASK_DATA_SIZE); | ||
697 | } | ||
698 | #endif | ||
699 | } | ||
700 | |||
701 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
702 | return err; | ||
703 | } | ||
704 | |||
705 | |||
706 | int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture) | ||
707 | { | ||
708 | int err; | ||
709 | unsigned long flags; | ||
710 | |||
711 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
712 | |||
713 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
714 | lx_message_init(&chip->rmh, CMD_09_STOP_PIPE); | ||
715 | |||
716 | chip->rmh.cmd[0] |= pipe_cmd; | ||
717 | |||
718 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
719 | |||
720 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
721 | return err; | ||
722 | } | ||
723 | |||
724 | static int lx_pipe_toggle_state(struct lx6464es *chip, u32 pipe, int is_capture) | ||
725 | { | ||
726 | int err; | ||
727 | unsigned long flags; | ||
728 | |||
729 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
730 | |||
731 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
732 | lx_message_init(&chip->rmh, CMD_0B_TOGGLE_PIPE_STATE); | ||
733 | |||
734 | chip->rmh.cmd[0] |= pipe_cmd; | ||
735 | |||
736 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
737 | |||
738 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
739 | return err; | ||
740 | } | ||
741 | |||
742 | |||
743 | int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture) | ||
744 | { | ||
745 | int err; | ||
746 | |||
747 | err = lx_pipe_wait_for_idle(chip, pipe, is_capture); | ||
748 | if (err < 0) | ||
749 | return err; | ||
750 | |||
751 | err = lx_pipe_toggle_state(chip, pipe, is_capture); | ||
752 | |||
753 | return err; | ||
754 | } | ||
755 | |||
756 | int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture) | ||
757 | { | ||
758 | int err = 0; | ||
759 | |||
760 | err = lx_pipe_wait_for_start(chip, pipe, is_capture); | ||
761 | if (err < 0) | ||
762 | return err; | ||
763 | |||
764 | err = lx_pipe_toggle_state(chip, pipe, is_capture); | ||
765 | |||
766 | return err; | ||
767 | } | ||
768 | |||
769 | |||
770 | int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, | ||
771 | u64 *rsample_count) | ||
772 | { | ||
773 | int err; | ||
774 | unsigned long flags; | ||
775 | |||
776 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
777 | |||
778 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
779 | lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); | ||
780 | |||
781 | chip->rmh.cmd[0] |= pipe_cmd; | ||
782 | chip->rmh.stat_len = 2; /* need all words here! */ | ||
783 | |||
784 | err = lx_message_send_atomic(chip, &chip->rmh); /* don't sleep! */ | ||
785 | |||
786 | if (err != 0) | ||
787 | snd_printk(KERN_ERR | ||
788 | "lx6464es: could not query pipe's sample count\n"); | ||
789 | else { | ||
790 | *rsample_count = ((u64)(chip->rmh.stat[0] & MASK_SPL_COUNT_HI) | ||
791 | << 24) /* hi part */ | ||
792 | + chip->rmh.stat[1]; /* lo part */ | ||
793 | } | ||
794 | |||
795 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
796 | return err; | ||
797 | } | ||
798 | |||
799 | int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate) | ||
800 | { | ||
801 | int err; | ||
802 | unsigned long flags; | ||
803 | |||
804 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
805 | |||
806 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
807 | lx_message_init(&chip->rmh, CMD_0A_GET_PIPE_SPL_COUNT); | ||
808 | |||
809 | chip->rmh.cmd[0] |= pipe_cmd; | ||
810 | |||
811 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
812 | |||
813 | if (err != 0) | ||
814 | snd_printk(KERN_ERR "lx6464es: could not query pipe's state\n"); | ||
815 | else | ||
816 | *rstate = (chip->rmh.stat[0] >> PSTATE_OFFSET) & 0x0F; | ||
817 | |||
818 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
819 | return err; | ||
820 | } | ||
821 | |||
822 | static int lx_pipe_wait_for_state(struct lx6464es *chip, u32 pipe, | ||
823 | int is_capture, u16 state) | ||
824 | { | ||
825 | int i; | ||
826 | |||
827 | /* max 2*PCMOnlyGranularity = 2*1024 at 44100 = < 50 ms: | ||
828 | * timeout 50 ms */ | ||
829 | for (i = 0; i != 50; ++i) { | ||
830 | u16 current_state; | ||
831 | int err = lx_pipe_state(chip, pipe, is_capture, ¤t_state); | ||
832 | |||
833 | if (err < 0) | ||
834 | return err; | ||
835 | |||
836 | if (current_state == state) | ||
837 | return 0; | ||
838 | |||
839 | mdelay(1); | ||
840 | } | ||
841 | |||
842 | return -ETIMEDOUT; | ||
843 | } | ||
844 | |||
845 | int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture) | ||
846 | { | ||
847 | return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_RUN); | ||
848 | } | ||
849 | |||
850 | int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture) | ||
851 | { | ||
852 | return lx_pipe_wait_for_state(chip, pipe, is_capture, PSTATE_IDLE); | ||
853 | } | ||
854 | |||
855 | /* low-level stream handling */ | ||
856 | int lx_stream_set_state(struct lx6464es *chip, u32 pipe, | ||
857 | int is_capture, enum stream_state_t state) | ||
858 | { | ||
859 | int err; | ||
860 | unsigned long flags; | ||
861 | |||
862 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
863 | |||
864 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
865 | lx_message_init(&chip->rmh, CMD_13_SET_STREAM_STATE); | ||
866 | |||
867 | chip->rmh.cmd[0] |= pipe_cmd; | ||
868 | chip->rmh.cmd[0] |= state; | ||
869 | |||
870 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
871 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
872 | |||
873 | return err; | ||
874 | } | ||
875 | |||
876 | int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, | ||
877 | u32 pipe, int is_capture) | ||
878 | { | ||
879 | int err; | ||
880 | unsigned long flags; | ||
881 | |||
882 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
883 | |||
884 | u32 channels = runtime->channels; | ||
885 | |||
886 | if (runtime->channels != channels) | ||
887 | snd_printk(KERN_ERR LXP "channel count mismatch: %d vs %d", | ||
888 | runtime->channels, channels); | ||
889 | |||
890 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
891 | lx_message_init(&chip->rmh, CMD_0C_DEF_STREAM); | ||
892 | |||
893 | chip->rmh.cmd[0] |= pipe_cmd; | ||
894 | |||
895 | if (runtime->sample_bits == 16) | ||
896 | /* 16 bit format */ | ||
897 | chip->rmh.cmd[0] |= (STREAM_FMT_16b << STREAM_FMT_OFFSET); | ||
898 | |||
899 | if (snd_pcm_format_little_endian(runtime->format)) | ||
900 | /* little endian/intel format */ | ||
901 | chip->rmh.cmd[0] |= (STREAM_FMT_intel << STREAM_FMT_OFFSET); | ||
902 | |||
903 | chip->rmh.cmd[0] |= channels-1; | ||
904 | |||
905 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
906 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
907 | |||
908 | return err; | ||
909 | } | ||
910 | |||
911 | int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, | ||
912 | int *rstate) | ||
913 | { | ||
914 | int err; | ||
915 | unsigned long flags; | ||
916 | |||
917 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
918 | |||
919 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
920 | lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); | ||
921 | |||
922 | chip->rmh.cmd[0] |= pipe_cmd; | ||
923 | |||
924 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
925 | |||
926 | *rstate = (chip->rmh.stat[0] & SF_START) ? START_STATE : PAUSE_STATE; | ||
927 | |||
928 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
929 | return err; | ||
930 | } | ||
931 | |||
932 | int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, | ||
933 | u64 *r_bytepos) | ||
934 | { | ||
935 | int err; | ||
936 | unsigned long flags; | ||
937 | |||
938 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
939 | |||
940 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
941 | lx_message_init(&chip->rmh, CMD_0E_GET_STREAM_SPL_COUNT); | ||
942 | |||
943 | chip->rmh.cmd[0] |= pipe_cmd; | ||
944 | |||
945 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
946 | |||
947 | *r_bytepos = ((u64) (chip->rmh.stat[0] & MASK_SPL_COUNT_HI) | ||
948 | << 32) /* hi part */ | ||
949 | + chip->rmh.stat[1]; /* lo part */ | ||
950 | |||
951 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
952 | return err; | ||
953 | } | ||
954 | |||
955 | /* low-level buffer handling */ | ||
956 | int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, | ||
957 | u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi, | ||
958 | u32 *r_buffer_index) | ||
959 | { | ||
960 | int err; | ||
961 | unsigned long flags; | ||
962 | |||
963 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
964 | |||
965 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
966 | lx_message_init(&chip->rmh, CMD_0F_UPDATE_BUFFER); | ||
967 | |||
968 | chip->rmh.cmd[0] |= pipe_cmd; | ||
969 | chip->rmh.cmd[0] |= BF_NOTIFY_EOB; /* request interrupt notification */ | ||
970 | |||
971 | /* todo: pause request, circular buffer */ | ||
972 | |||
973 | chip->rmh.cmd[1] = buffer_size & MASK_DATA_SIZE; | ||
974 | chip->rmh.cmd[2] = buf_address_lo; | ||
975 | |||
976 | if (buf_address_hi) { | ||
977 | chip->rmh.cmd_len = 4; | ||
978 | chip->rmh.cmd[3] = buf_address_hi; | ||
979 | chip->rmh.cmd[0] |= BF_64BITS_ADR; | ||
980 | } | ||
981 | |||
982 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
983 | |||
984 | if (err == 0) { | ||
985 | *r_buffer_index = chip->rmh.stat[0]; | ||
986 | goto done; | ||
987 | } | ||
988 | |||
989 | if (err == EB_RBUFFERS_TABLE_OVERFLOW) | ||
990 | snd_printk(LXP "lx_buffer_give EB_RBUFFERS_TABLE_OVERFLOW\n"); | ||
991 | |||
992 | if (err == EB_INVALID_STREAM) | ||
993 | snd_printk(LXP "lx_buffer_give EB_INVALID_STREAM\n"); | ||
994 | |||
995 | if (err == EB_CMD_REFUSED) | ||
996 | snd_printk(LXP "lx_buffer_give EB_CMD_REFUSED\n"); | ||
997 | |||
998 | done: | ||
999 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
1000 | return err; | ||
1001 | } | ||
1002 | |||
1003 | int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, | ||
1004 | u32 *r_buffer_size) | ||
1005 | { | ||
1006 | int err; | ||
1007 | unsigned long flags; | ||
1008 | |||
1009 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
1010 | |||
1011 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
1012 | lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); | ||
1013 | |||
1014 | chip->rmh.cmd[0] |= pipe_cmd; | ||
1015 | chip->rmh.cmd[0] |= MASK_BUFFER_ID; /* ask for the current buffer: the | ||
1016 | * microblaze will seek for it */ | ||
1017 | |||
1018 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
1019 | |||
1020 | if (err == 0) | ||
1021 | *r_buffer_size = chip->rmh.stat[0] & MASK_DATA_SIZE; | ||
1022 | |||
1023 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
1024 | return err; | ||
1025 | } | ||
1026 | |||
1027 | int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, | ||
1028 | u32 buffer_index) | ||
1029 | { | ||
1030 | int err; | ||
1031 | unsigned long flags; | ||
1032 | |||
1033 | u32 pipe_cmd = PIPE_INFO_TO_CMD(is_capture, pipe); | ||
1034 | |||
1035 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
1036 | lx_message_init(&chip->rmh, CMD_11_CANCEL_BUFFER); | ||
1037 | |||
1038 | chip->rmh.cmd[0] |= pipe_cmd; | ||
1039 | chip->rmh.cmd[0] |= buffer_index; | ||
1040 | |||
1041 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
1042 | |||
1043 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
1044 | return err; | ||
1045 | } | ||
1046 | |||
1047 | |||
1048 | /* low-level gain/peak handling | ||
1049 | * | ||
1050 | * \todo: can we unmute capture/playback channels independently? | ||
1051 | * | ||
1052 | * */ | ||
1053 | int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute) | ||
1054 | { | ||
1055 | int err; | ||
1056 | unsigned long flags; | ||
1057 | |||
1058 | /* bit set to 1: channel muted */ | ||
1059 | u64 mute_mask = unmute ? 0 : 0xFFFFFFFFFFFFFFFFLLU; | ||
1060 | |||
1061 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
1062 | lx_message_init(&chip->rmh, CMD_0D_SET_MUTE); | ||
1063 | |||
1064 | chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, 0); | ||
1065 | |||
1066 | chip->rmh.cmd[1] = (u32)(mute_mask >> (u64)32); /* hi part */ | ||
1067 | chip->rmh.cmd[2] = (u32)(mute_mask & (u64)0xFFFFFFFF); /* lo part */ | ||
1068 | |||
1069 | snd_printk("mute %x %x %x\n", chip->rmh.cmd[0], chip->rmh.cmd[1], | ||
1070 | chip->rmh.cmd[2]); | ||
1071 | |||
1072 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
1073 | |||
1074 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
1075 | return err; | ||
1076 | } | ||
1077 | |||
1078 | static u32 peak_map[] = { | ||
1079 | 0x00000109, /* -90.308dB */ | ||
1080 | 0x0000083B, /* -72.247dB */ | ||
1081 | 0x000020C4, /* -60.205dB */ | ||
1082 | 0x00008273, /* -48.030dB */ | ||
1083 | 0x00020756, /* -36.005dB */ | ||
1084 | 0x00040C37, /* -30.001dB */ | ||
1085 | 0x00081385, /* -24.002dB */ | ||
1086 | 0x00101D3F, /* -18.000dB */ | ||
1087 | 0x0016C310, /* -15.000dB */ | ||
1088 | 0x002026F2, /* -12.001dB */ | ||
1089 | 0x002D6A86, /* -9.000dB */ | ||
1090 | 0x004026E6, /* -6.004dB */ | ||
1091 | 0x005A9DF6, /* -3.000dB */ | ||
1092 | 0x0065AC8B, /* -2.000dB */ | ||
1093 | 0x00721481, /* -1.000dB */ | ||
1094 | 0x007FFFFF, /* FS */ | ||
1095 | }; | ||
1096 | |||
1097 | int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, | ||
1098 | u32 *r_levels) | ||
1099 | { | ||
1100 | int err = 0; | ||
1101 | unsigned long flags; | ||
1102 | int i; | ||
1103 | spin_lock_irqsave(&chip->msg_lock, flags); | ||
1104 | |||
1105 | for (i = 0; i < channels; i += 4) { | ||
1106 | u32 s0, s1, s2, s3; | ||
1107 | |||
1108 | lx_message_init(&chip->rmh, CMD_12_GET_PEAK); | ||
1109 | chip->rmh.cmd[0] |= PIPE_INFO_TO_CMD(is_capture, i); | ||
1110 | |||
1111 | err = lx_message_send_atomic(chip, &chip->rmh); | ||
1112 | |||
1113 | if (err == 0) { | ||
1114 | s0 = peak_map[chip->rmh.stat[0] & 0x0F]; | ||
1115 | s1 = peak_map[(chip->rmh.stat[0] >> 4) & 0xf]; | ||
1116 | s2 = peak_map[(chip->rmh.stat[0] >> 8) & 0xf]; | ||
1117 | s3 = peak_map[(chip->rmh.stat[0] >> 12) & 0xf]; | ||
1118 | } else | ||
1119 | s0 = s1 = s2 = s3 = 0; | ||
1120 | |||
1121 | r_levels[0] = s0; | ||
1122 | r_levels[1] = s1; | ||
1123 | r_levels[2] = s2; | ||
1124 | r_levels[3] = s3; | ||
1125 | |||
1126 | r_levels += 4; | ||
1127 | } | ||
1128 | |||
1129 | spin_unlock_irqrestore(&chip->msg_lock, flags); | ||
1130 | return err; | ||
1131 | } | ||
1132 | |||
1133 | /* interrupt handling */ | ||
1134 | #define PCX_IRQ_NONE 0 | ||
1135 | #define IRQCS_ACTIVE_PCIDB 0x00002000L /* Bit nø 13 */ | ||
1136 | #define IRQCS_ENABLE_PCIIRQ 0x00000100L /* Bit nø 08 */ | ||
1137 | #define IRQCS_ENABLE_PCIDB 0x00000200L /* Bit nø 09 */ | ||
1138 | |||
1139 | static u32 lx_interrupt_test_ack(struct lx6464es *chip) | ||
1140 | { | ||
1141 | u32 irqcs = lx_plx_reg_read(chip, ePLX_IRQCS); | ||
1142 | |||
1143 | /* Test if PCI Doorbell interrupt is active */ | ||
1144 | if (irqcs & IRQCS_ACTIVE_PCIDB) { | ||
1145 | u32 temp; | ||
1146 | irqcs = PCX_IRQ_NONE; | ||
1147 | |||
1148 | while ((temp = lx_plx_reg_read(chip, ePLX_L2PCIDB))) { | ||
1149 | /* RAZ interrupt */ | ||
1150 | irqcs |= temp; | ||
1151 | lx_plx_reg_write(chip, ePLX_L2PCIDB, temp); | ||
1152 | } | ||
1153 | |||
1154 | return irqcs; | ||
1155 | } | ||
1156 | return PCX_IRQ_NONE; | ||
1157 | } | ||
1158 | |||
1159 | static int lx_interrupt_ack(struct lx6464es *chip, u32 *r_irqsrc, | ||
1160 | int *r_async_pending, int *r_async_escmd) | ||
1161 | { | ||
1162 | u32 irq_async; | ||
1163 | u32 irqsrc = lx_interrupt_test_ack(chip); | ||
1164 | |||
1165 | if (irqsrc == PCX_IRQ_NONE) | ||
1166 | return 0; | ||
1167 | |||
1168 | *r_irqsrc = irqsrc; | ||
1169 | |||
1170 | irq_async = irqsrc & MASK_SYS_ASYNC_EVENTS; /* + EtherSound response | ||
1171 | * (set by xilinx) + EOB */ | ||
1172 | |||
1173 | if (irq_async & MASK_SYS_STATUS_ESA) { | ||
1174 | irq_async &= ~MASK_SYS_STATUS_ESA; | ||
1175 | *r_async_escmd = 1; | ||
1176 | } | ||
1177 | |||
1178 | if (irqsrc & MASK_SYS_STATUS_CMD_DONE) | ||
1179 | /* xilinx command notification */ | ||
1180 | atomic_set(&chip->send_message_locked, 0); | ||
1181 | |||
1182 | if (irq_async) { | ||
1183 | /* snd_printd("interrupt: async event pending\n"); */ | ||
1184 | *r_async_pending = 1; | ||
1185 | } | ||
1186 | |||
1187 | return 1; | ||
1188 | } | ||
1189 | |||
1190 | static int lx_interrupt_handle_async_events(struct lx6464es *chip, u32 irqsrc, | ||
1191 | int *r_freq_changed, | ||
1192 | u64 *r_notified_in_pipe_mask, | ||
1193 | u64 *r_notified_out_pipe_mask) | ||
1194 | { | ||
1195 | int err; | ||
1196 | u32 stat[9]; /* answer from CMD_04_GET_EVENT */ | ||
1197 | |||
1198 | /* On peut optimiser pour ne pas lire les evenements vides | ||
1199 | * les mots de réponse sont dans l'ordre suivant : | ||
1200 | * Stat[0] mot de status général | ||
1201 | * Stat[1] fin de buffer OUT pF | ||
1202 | * Stat[2] fin de buffer OUT pf | ||
1203 | * Stat[3] fin de buffer IN pF | ||
1204 | * Stat[4] fin de buffer IN pf | ||
1205 | * Stat[5] underrun poid fort | ||
1206 | * Stat[6] underrun poid faible | ||
1207 | * Stat[7] overrun poid fort | ||
1208 | * Stat[8] overrun poid faible | ||
1209 | * */ | ||
1210 | |||
1211 | u64 orun_mask; | ||
1212 | u64 urun_mask; | ||
1213 | #if 0 | ||
1214 | int has_underrun = (irqsrc & MASK_SYS_STATUS_URUN) ? 1 : 0; | ||
1215 | int has_overrun = (irqsrc & MASK_SYS_STATUS_ORUN) ? 1 : 0; | ||
1216 | #endif | ||
1217 | int eb_pending_out = (irqsrc & MASK_SYS_STATUS_EOBO) ? 1 : 0; | ||
1218 | int eb_pending_in = (irqsrc & MASK_SYS_STATUS_EOBI) ? 1 : 0; | ||
1219 | |||
1220 | *r_freq_changed = (irqsrc & MASK_SYS_STATUS_FREQ) ? 1 : 0; | ||
1221 | |||
1222 | err = lx_dsp_read_async_events(chip, stat); | ||
1223 | if (err < 0) | ||
1224 | return err; | ||
1225 | |||
1226 | if (eb_pending_in) { | ||
1227 | *r_notified_in_pipe_mask = ((u64)stat[3] << 32) | ||
1228 | + stat[4]; | ||
1229 | snd_printdd(LXP "interrupt: EOBI pending %llx\n", | ||
1230 | *r_notified_in_pipe_mask); | ||
1231 | } | ||
1232 | if (eb_pending_out) { | ||
1233 | *r_notified_out_pipe_mask = ((u64)stat[1] << 32) | ||
1234 | + stat[2]; | ||
1235 | snd_printdd(LXP "interrupt: EOBO pending %llx\n", | ||
1236 | *r_notified_out_pipe_mask); | ||
1237 | } | ||
1238 | |||
1239 | orun_mask = ((u64)stat[7] << 32) + stat[8]; | ||
1240 | urun_mask = ((u64)stat[5] << 32) + stat[6]; | ||
1241 | |||
1242 | /* todo: handle xrun notification */ | ||
1243 | |||
1244 | return err; | ||
1245 | } | ||
1246 | |||
1247 | static int lx_interrupt_request_new_buffer(struct lx6464es *chip, | ||
1248 | struct lx_stream *lx_stream) | ||
1249 | { | ||
1250 | struct snd_pcm_substream *substream = lx_stream->stream; | ||
1251 | int is_capture = lx_stream->is_capture; | ||
1252 | int err; | ||
1253 | unsigned long flags; | ||
1254 | |||
1255 | const u32 channels = substream->runtime->channels; | ||
1256 | const u32 bytes_per_frame = channels * 3; | ||
1257 | const u32 period_size = substream->runtime->period_size; | ||
1258 | const u32 period_bytes = period_size * bytes_per_frame; | ||
1259 | const u32 pos = lx_stream->frame_pos; | ||
1260 | const u32 next_pos = ((pos+1) == substream->runtime->periods) ? | ||
1261 | 0 : pos + 1; | ||
1262 | |||
1263 | dma_addr_t buf = substream->dma_buffer.addr + pos * period_bytes; | ||
1264 | u32 buf_hi = 0; | ||
1265 | u32 buf_lo = 0; | ||
1266 | u32 buffer_index = 0; | ||
1267 | |||
1268 | u32 needed, freed; | ||
1269 | u32 size_array[MAX_STREAM_BUFFER]; | ||
1270 | |||
1271 | snd_printdd("->lx_interrupt_request_new_buffer\n"); | ||
1272 | |||
1273 | spin_lock_irqsave(&chip->lock, flags); | ||
1274 | |||
1275 | err = lx_buffer_ask(chip, 0, is_capture, &needed, &freed, size_array); | ||
1276 | snd_printdd(LXP "interrupt: needed %d, freed %d\n", needed, freed); | ||
1277 | |||
1278 | unpack_pointer(buf, &buf_lo, &buf_hi); | ||
1279 | err = lx_buffer_give(chip, 0, is_capture, period_bytes, buf_lo, buf_hi, | ||
1280 | &buffer_index); | ||
1281 | snd_printdd(LXP "interrupt: gave buffer index %x on %p (%d bytes)\n", | ||
1282 | buffer_index, (void *)buf, period_bytes); | ||
1283 | |||
1284 | lx_stream->frame_pos = next_pos; | ||
1285 | spin_unlock_irqrestore(&chip->lock, flags); | ||
1286 | |||
1287 | return err; | ||
1288 | } | ||
1289 | |||
1290 | void lx_tasklet_playback(unsigned long data) | ||
1291 | { | ||
1292 | struct lx6464es *chip = (struct lx6464es *)data; | ||
1293 | struct lx_stream *lx_stream = &chip->playback_stream; | ||
1294 | int err; | ||
1295 | |||
1296 | snd_printdd("->lx_tasklet_playback\n"); | ||
1297 | |||
1298 | err = lx_interrupt_request_new_buffer(chip, lx_stream); | ||
1299 | if (err < 0) | ||
1300 | snd_printk(KERN_ERR LXP | ||
1301 | "cannot request new buffer for playback\n"); | ||
1302 | |||
1303 | snd_pcm_period_elapsed(lx_stream->stream); | ||
1304 | } | ||
1305 | |||
1306 | void lx_tasklet_capture(unsigned long data) | ||
1307 | { | ||
1308 | struct lx6464es *chip = (struct lx6464es *)data; | ||
1309 | struct lx_stream *lx_stream = &chip->capture_stream; | ||
1310 | int err; | ||
1311 | |||
1312 | snd_printdd("->lx_tasklet_capture\n"); | ||
1313 | err = lx_interrupt_request_new_buffer(chip, lx_stream); | ||
1314 | if (err < 0) | ||
1315 | snd_printk(KERN_ERR LXP | ||
1316 | "cannot request new buffer for capture\n"); | ||
1317 | |||
1318 | snd_pcm_period_elapsed(lx_stream->stream); | ||
1319 | } | ||
1320 | |||
1321 | |||
1322 | |||
1323 | static int lx_interrupt_handle_audio_transfer(struct lx6464es *chip, | ||
1324 | u64 notified_in_pipe_mask, | ||
1325 | u64 notified_out_pipe_mask) | ||
1326 | { | ||
1327 | int err = 0; | ||
1328 | |||
1329 | if (notified_in_pipe_mask) { | ||
1330 | snd_printdd(LXP "requesting audio transfer for capture\n"); | ||
1331 | tasklet_hi_schedule(&chip->tasklet_capture); | ||
1332 | } | ||
1333 | |||
1334 | if (notified_out_pipe_mask) { | ||
1335 | snd_printdd(LXP "requesting audio transfer for playback\n"); | ||
1336 | tasklet_hi_schedule(&chip->tasklet_playback); | ||
1337 | } | ||
1338 | |||
1339 | return err; | ||
1340 | } | ||
1341 | |||
1342 | |||
1343 | irqreturn_t lx_interrupt(int irq, void *dev_id) | ||
1344 | { | ||
1345 | struct lx6464es *chip = dev_id; | ||
1346 | int async_pending, async_escmd; | ||
1347 | u32 irqsrc; | ||
1348 | |||
1349 | spin_lock(&chip->lock); | ||
1350 | |||
1351 | snd_printdd("**************************************************\n"); | ||
1352 | |||
1353 | if (!lx_interrupt_ack(chip, &irqsrc, &async_pending, &async_escmd)) { | ||
1354 | spin_unlock(&chip->lock); | ||
1355 | snd_printdd("IRQ_NONE\n"); | ||
1356 | return IRQ_NONE; /* this device did not cause the interrupt */ | ||
1357 | } | ||
1358 | |||
1359 | if (irqsrc & MASK_SYS_STATUS_CMD_DONE) | ||
1360 | goto exit; | ||
1361 | |||
1362 | #if 0 | ||
1363 | if (irqsrc & MASK_SYS_STATUS_EOBI) | ||
1364 | snd_printdd(LXP "interrupt: EOBI\n"); | ||
1365 | |||
1366 | if (irqsrc & MASK_SYS_STATUS_EOBO) | ||
1367 | snd_printdd(LXP "interrupt: EOBO\n"); | ||
1368 | |||
1369 | if (irqsrc & MASK_SYS_STATUS_URUN) | ||
1370 | snd_printdd(LXP "interrupt: URUN\n"); | ||
1371 | |||
1372 | if (irqsrc & MASK_SYS_STATUS_ORUN) | ||
1373 | snd_printdd(LXP "interrupt: ORUN\n"); | ||
1374 | #endif | ||
1375 | |||
1376 | if (async_pending) { | ||
1377 | u64 notified_in_pipe_mask = 0; | ||
1378 | u64 notified_out_pipe_mask = 0; | ||
1379 | int freq_changed; | ||
1380 | int err; | ||
1381 | |||
1382 | /* handle async events */ | ||
1383 | err = lx_interrupt_handle_async_events(chip, irqsrc, | ||
1384 | &freq_changed, | ||
1385 | ¬ified_in_pipe_mask, | ||
1386 | ¬ified_out_pipe_mask); | ||
1387 | if (err) | ||
1388 | snd_printk(KERN_ERR LXP | ||
1389 | "error handling async events\n"); | ||
1390 | |||
1391 | err = lx_interrupt_handle_audio_transfer(chip, | ||
1392 | notified_in_pipe_mask, | ||
1393 | notified_out_pipe_mask | ||
1394 | ); | ||
1395 | if (err) | ||
1396 | snd_printk(KERN_ERR LXP | ||
1397 | "error during audio transfer\n"); | ||
1398 | } | ||
1399 | |||
1400 | if (async_escmd) { | ||
1401 | #if 0 | ||
1402 | /* backdoor for ethersound commands | ||
1403 | * | ||
1404 | * for now, we do not need this | ||
1405 | * | ||
1406 | * */ | ||
1407 | |||
1408 | snd_printdd("lx6464es: interrupt requests escmd handling\n"); | ||
1409 | #endif | ||
1410 | } | ||
1411 | |||
1412 | exit: | ||
1413 | spin_unlock(&chip->lock); | ||
1414 | return IRQ_HANDLED; /* this device caused the interrupt */ | ||
1415 | } | ||
1416 | |||
1417 | |||
1418 | static void lx_irq_set(struct lx6464es *chip, int enable) | ||
1419 | { | ||
1420 | u32 reg = lx_plx_reg_read(chip, ePLX_IRQCS); | ||
1421 | |||
1422 | /* enable/disable interrupts | ||
1423 | * | ||
1424 | * Set the Doorbell and PCI interrupt enable bits | ||
1425 | * | ||
1426 | * */ | ||
1427 | if (enable) | ||
1428 | reg |= (IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); | ||
1429 | else | ||
1430 | reg &= ~(IRQCS_ENABLE_PCIIRQ | IRQCS_ENABLE_PCIDB); | ||
1431 | lx_plx_reg_write(chip, ePLX_IRQCS, reg); | ||
1432 | } | ||
1433 | |||
1434 | void lx_irq_enable(struct lx6464es *chip) | ||
1435 | { | ||
1436 | snd_printdd("->lx_irq_enable\n"); | ||
1437 | lx_irq_set(chip, 1); | ||
1438 | } | ||
1439 | |||
1440 | void lx_irq_disable(struct lx6464es *chip) | ||
1441 | { | ||
1442 | snd_printdd("->lx_irq_disable\n"); | ||
1443 | lx_irq_set(chip, 0); | ||
1444 | } | ||
diff --git a/sound/pci/lx6464es/lx_core.h b/sound/pci/lx6464es/lx_core.h new file mode 100644 index 000000000000..6bd9cbbbc68d --- /dev/null +++ b/sound/pci/lx6464es/lx_core.h | |||
@@ -0,0 +1,242 @@ | |||
1 | /* -*- linux-c -*- * | ||
2 | * | ||
3 | * ALSA driver for the digigram lx6464es interface | ||
4 | * low-level interface | ||
5 | * | ||
6 | * Copyright (c) 2009 Tim Blechmann <tim@klingt.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, write to | ||
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
21 | * Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef LX_CORE_H | ||
26 | #define LX_CORE_H | ||
27 | |||
28 | #include <linux/interrupt.h> | ||
29 | |||
30 | #include "lx_defs.h" | ||
31 | |||
32 | #define REG_CRM_NUMBER 12 | ||
33 | |||
34 | struct lx6464es; | ||
35 | |||
36 | /* low-level register access */ | ||
37 | |||
38 | /* dsp register access */ | ||
39 | enum { | ||
40 | eReg_BASE, | ||
41 | eReg_CSM, | ||
42 | eReg_CRM1, | ||
43 | eReg_CRM2, | ||
44 | eReg_CRM3, | ||
45 | eReg_CRM4, | ||
46 | eReg_CRM5, | ||
47 | eReg_CRM6, | ||
48 | eReg_CRM7, | ||
49 | eReg_CRM8, | ||
50 | eReg_CRM9, | ||
51 | eReg_CRM10, | ||
52 | eReg_CRM11, | ||
53 | eReg_CRM12, | ||
54 | |||
55 | eReg_ICR, | ||
56 | eReg_CVR, | ||
57 | eReg_ISR, | ||
58 | eReg_RXHTXH, | ||
59 | eReg_RXMTXM, | ||
60 | eReg_RHLTXL, | ||
61 | eReg_RESETDSP, | ||
62 | |||
63 | eReg_CSUF, | ||
64 | eReg_CSES, | ||
65 | eReg_CRESMSB, | ||
66 | eReg_CRESLSB, | ||
67 | eReg_ADMACESMSB, | ||
68 | eReg_ADMACESLSB, | ||
69 | eReg_CONFES, | ||
70 | |||
71 | eMaxPortLx | ||
72 | }; | ||
73 | |||
74 | unsigned long lx_dsp_reg_read(struct lx6464es *chip, int port); | ||
75 | void lx_dsp_reg_readbuf(struct lx6464es *chip, int port, u32 *data, u32 len); | ||
76 | void lx_dsp_reg_write(struct lx6464es *chip, int port, unsigned data); | ||
77 | void lx_dsp_reg_writebuf(struct lx6464es *chip, int port, const u32 *data, | ||
78 | u32 len); | ||
79 | |||
80 | /* plx register access */ | ||
81 | enum { | ||
82 | ePLX_PCICR, | ||
83 | |||
84 | ePLX_MBOX0, | ||
85 | ePLX_MBOX1, | ||
86 | ePLX_MBOX2, | ||
87 | ePLX_MBOX3, | ||
88 | ePLX_MBOX4, | ||
89 | ePLX_MBOX5, | ||
90 | ePLX_MBOX6, | ||
91 | ePLX_MBOX7, | ||
92 | |||
93 | ePLX_L2PCIDB, | ||
94 | ePLX_IRQCS, | ||
95 | ePLX_CHIPSC, | ||
96 | |||
97 | eMaxPort | ||
98 | }; | ||
99 | |||
100 | unsigned long lx_plx_reg_read(struct lx6464es *chip, int port); | ||
101 | void lx_plx_reg_write(struct lx6464es *chip, int port, u32 data); | ||
102 | |||
103 | /* rhm */ | ||
104 | struct lx_rmh { | ||
105 | u16 cmd_len; /* length of the command to send (WORDs) */ | ||
106 | u16 stat_len; /* length of the status received (WORDs) */ | ||
107 | u16 dsp_stat; /* status type, RMP_SSIZE_XXX */ | ||
108 | u16 cmd_idx; /* index of the command */ | ||
109 | u32 cmd[REG_CRM_NUMBER]; | ||
110 | u32 stat[REG_CRM_NUMBER]; | ||
111 | }; | ||
112 | |||
113 | |||
114 | /* low-level dsp access */ | ||
115 | int __devinit lx_dsp_get_version(struct lx6464es *chip, u32 *rdsp_version); | ||
116 | int lx_dsp_get_clock_frequency(struct lx6464es *chip, u32 *rfreq); | ||
117 | int lx_dsp_set_granularity(struct lx6464es *chip, u32 gran); | ||
118 | int lx_dsp_read_async_events(struct lx6464es *chip, u32 *data); | ||
119 | int lx_dsp_get_mac(struct lx6464es *chip, u8 *mac_address); | ||
120 | |||
121 | |||
122 | /* low-level pipe handling */ | ||
123 | int lx_pipe_allocate(struct lx6464es *chip, u32 pipe, int is_capture, | ||
124 | int channels); | ||
125 | int lx_pipe_release(struct lx6464es *chip, u32 pipe, int is_capture); | ||
126 | int lx_pipe_sample_count(struct lx6464es *chip, u32 pipe, int is_capture, | ||
127 | u64 *rsample_count); | ||
128 | int lx_pipe_state(struct lx6464es *chip, u32 pipe, int is_capture, u16 *rstate); | ||
129 | int lx_pipe_stop(struct lx6464es *chip, u32 pipe, int is_capture); | ||
130 | int lx_pipe_start(struct lx6464es *chip, u32 pipe, int is_capture); | ||
131 | int lx_pipe_pause(struct lx6464es *chip, u32 pipe, int is_capture); | ||
132 | |||
133 | int lx_pipe_wait_for_start(struct lx6464es *chip, u32 pipe, int is_capture); | ||
134 | int lx_pipe_wait_for_idle(struct lx6464es *chip, u32 pipe, int is_capture); | ||
135 | |||
136 | /* low-level stream handling */ | ||
137 | int lx_stream_set_format(struct lx6464es *chip, struct snd_pcm_runtime *runtime, | ||
138 | u32 pipe, int is_capture); | ||
139 | int lx_stream_state(struct lx6464es *chip, u32 pipe, int is_capture, | ||
140 | int *rstate); | ||
141 | int lx_stream_sample_position(struct lx6464es *chip, u32 pipe, int is_capture, | ||
142 | u64 *r_bytepos); | ||
143 | |||
144 | int lx_stream_set_state(struct lx6464es *chip, u32 pipe, | ||
145 | int is_capture, enum stream_state_t state); | ||
146 | |||
147 | static inline int lx_stream_start(struct lx6464es *chip, u32 pipe, | ||
148 | int is_capture) | ||
149 | { | ||
150 | snd_printdd("->lx_stream_start\n"); | ||
151 | return lx_stream_set_state(chip, pipe, is_capture, SSTATE_RUN); | ||
152 | } | ||
153 | |||
154 | static inline int lx_stream_pause(struct lx6464es *chip, u32 pipe, | ||
155 | int is_capture) | ||
156 | { | ||
157 | snd_printdd("->lx_stream_pause\n"); | ||
158 | return lx_stream_set_state(chip, pipe, is_capture, SSTATE_PAUSE); | ||
159 | } | ||
160 | |||
161 | static inline int lx_stream_stop(struct lx6464es *chip, u32 pipe, | ||
162 | int is_capture) | ||
163 | { | ||
164 | snd_printdd("->lx_stream_stop\n"); | ||
165 | return lx_stream_set_state(chip, pipe, is_capture, SSTATE_STOP); | ||
166 | } | ||
167 | |||
168 | /* low-level buffer handling */ | ||
169 | int lx_buffer_ask(struct lx6464es *chip, u32 pipe, int is_capture, | ||
170 | u32 *r_needed, u32 *r_freed, u32 *size_array); | ||
171 | int lx_buffer_give(struct lx6464es *chip, u32 pipe, int is_capture, | ||
172 | u32 buffer_size, u32 buf_address_lo, u32 buf_address_hi, | ||
173 | u32 *r_buffer_index); | ||
174 | int lx_buffer_free(struct lx6464es *chip, u32 pipe, int is_capture, | ||
175 | u32 *r_buffer_size); | ||
176 | int lx_buffer_cancel(struct lx6464es *chip, u32 pipe, int is_capture, | ||
177 | u32 buffer_index); | ||
178 | |||
179 | /* low-level gain/peak handling */ | ||
180 | int lx_level_unmute(struct lx6464es *chip, int is_capture, int unmute); | ||
181 | int lx_level_peaks(struct lx6464es *chip, int is_capture, int channels, | ||
182 | u32 *r_levels); | ||
183 | |||
184 | |||
185 | /* interrupt handling */ | ||
186 | irqreturn_t lx_interrupt(int irq, void *dev_id); | ||
187 | void lx_irq_enable(struct lx6464es *chip); | ||
188 | void lx_irq_disable(struct lx6464es *chip); | ||
189 | |||
190 | void lx_tasklet_capture(unsigned long data); | ||
191 | void lx_tasklet_playback(unsigned long data); | ||
192 | |||
193 | |||
194 | /* Stream Format Header Defines (for LIN and IEEE754) */ | ||
195 | #define HEADER_FMT_BASE HEADER_FMT_BASE_LIN | ||
196 | #define HEADER_FMT_BASE_LIN 0xFED00000 | ||
197 | #define HEADER_FMT_BASE_FLOAT 0xFAD00000 | ||
198 | #define HEADER_FMT_MONO 0x00000080 /* bit 23 in header_lo. WARNING: old | ||
199 | * bit 22 is ignored in float | ||
200 | * format */ | ||
201 | #define HEADER_FMT_INTEL 0x00008000 | ||
202 | #define HEADER_FMT_16BITS 0x00002000 | ||
203 | #define HEADER_FMT_24BITS 0x00004000 | ||
204 | #define HEADER_FMT_UPTO11 0x00000200 /* frequency is less or equ. to 11k. | ||
205 | * */ | ||
206 | #define HEADER_FMT_UPTO32 0x00000100 /* frequency is over 11k and less | ||
207 | * then 32k.*/ | ||
208 | |||
209 | |||
210 | #define BIT_FMP_HEADER 23 | ||
211 | #define BIT_FMP_SD 22 | ||
212 | #define BIT_FMP_MULTICHANNEL 19 | ||
213 | |||
214 | #define START_STATE 1 | ||
215 | #define PAUSE_STATE 0 | ||
216 | |||
217 | |||
218 | |||
219 | |||
220 | |||
221 | /* from PcxAll_e.h */ | ||
222 | /* Start/Pause condition for pipes (PCXStartPipe, PCXPausePipe) */ | ||
223 | #define START_PAUSE_IMMEDIATE 0 | ||
224 | #define START_PAUSE_ON_SYNCHRO 1 | ||
225 | #define START_PAUSE_ON_TIME_CODE 2 | ||
226 | |||
227 | |||
228 | /* Pipe / Stream state */ | ||
229 | #define START_STATE 1 | ||
230 | #define PAUSE_STATE 0 | ||
231 | |||
232 | static inline void unpack_pointer(dma_addr_t ptr, u32 *r_low, u32 *r_high) | ||
233 | { | ||
234 | *r_low = (u32)(ptr & 0xffffffff); | ||
235 | #if BITS_PER_LONG == 32 | ||
236 | *r_high = 0; | ||
237 | #else | ||
238 | *r_high = (u32)((u64)ptr>>32); | ||
239 | #endif | ||
240 | } | ||
241 | |||
242 | #endif /* LX_CORE_H */ | ||
diff --git a/sound/pci/lx6464es/lx_defs.h b/sound/pci/lx6464es/lx_defs.h new file mode 100644 index 000000000000..49d36bdd512c --- /dev/null +++ b/sound/pci/lx6464es/lx_defs.h | |||
@@ -0,0 +1,376 @@ | |||
1 | /* -*- linux-c -*- * | ||
2 | * | ||
3 | * ALSA driver for the digigram lx6464es interface | ||
4 | * adapted upstream headers | ||
5 | * | ||
6 | * Copyright (c) 2009 Tim Blechmann <tim@klingt.org> | ||
7 | * | ||
8 | * This program is free software; you can redistribute it and/or modify | ||
9 | * it under the terms of the GNU General Public License as published by | ||
10 | * the Free Software Foundation; either version 2 of the License, or | ||
11 | * (at your option) any later version. | ||
12 | * | ||
13 | * This program is distributed in the hope that it will be useful, | ||
14 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | * GNU General Public License for more details. | ||
17 | * | ||
18 | * You should have received a copy of the GNU General Public License | ||
19 | * along with this program; see the file COPYING. If not, write to | ||
20 | * the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | ||
21 | * Boston, MA 02111-1307, USA. | ||
22 | * | ||
23 | */ | ||
24 | |||
25 | #ifndef LX_DEFS_H | ||
26 | #define LX_DEFS_H | ||
27 | |||
28 | /* code adapted from ethersound.h */ | ||
29 | #define XES_FREQ_COUNT8_MASK 0x00001FFF /* compteur 25MHz entre 8 ech. */ | ||
30 | #define XES_FREQ_COUNT8_44_MIN 0x00001288 /* 25M / | ||
31 | * [ 44k - ( 44.1k + 48k ) / 2 ] | ||
32 | * * 8 */ | ||
33 | #define XES_FREQ_COUNT8_44_MAX 0x000010F0 /* 25M / [ ( 44.1k + 48k ) / 2 ] | ||
34 | * * 8 */ | ||
35 | #define XES_FREQ_COUNT8_48_MAX 0x00000F08 /* 25M / | ||
36 | * [ 48k + ( 44.1k + 48k ) / 2 ] | ||
37 | * * 8 */ | ||
38 | |||
39 | /* code adapted from LXES_registers.h */ | ||
40 | |||
41 | #define IOCR_OUTPUTS_OFFSET 0 /* (rw) offset for the number of OUTs in the | ||
42 | * ConfES register. */ | ||
43 | #define IOCR_INPUTS_OFFSET 8 /* (rw) offset for the number of INs in the | ||
44 | * ConfES register. */ | ||
45 | #define FREQ_RATIO_OFFSET 19 /* (rw) offset for frequency ratio in the | ||
46 | * ConfES register. */ | ||
47 | #define FREQ_RATIO_SINGLE_MODE 0x01 /* value for single mode frequency ratio: | ||
48 | * sample rate = frequency rate. */ | ||
49 | |||
50 | #define CONFES_READ_PART_MASK 0x00070000 | ||
51 | #define CONFES_WRITE_PART_MASK 0x00F80000 | ||
52 | |||
53 | /* code adapted from if_drv_mb.h */ | ||
54 | |||
55 | #define MASK_SYS_STATUS_ERROR (1L << 31) /* events that lead to a PCI irq if | ||
56 | * not yet pending */ | ||
57 | #define MASK_SYS_STATUS_URUN (1L << 30) | ||
58 | #define MASK_SYS_STATUS_ORUN (1L << 29) | ||
59 | #define MASK_SYS_STATUS_EOBO (1L << 28) | ||
60 | #define MASK_SYS_STATUS_EOBI (1L << 27) | ||
61 | #define MASK_SYS_STATUS_FREQ (1L << 26) | ||
62 | #define MASK_SYS_STATUS_ESA (1L << 25) /* reserved, this is set by the | ||
63 | * XES */ | ||
64 | #define MASK_SYS_STATUS_TIMER (1L << 24) | ||
65 | |||
66 | #define MASK_SYS_ASYNC_EVENTS (MASK_SYS_STATUS_ERROR | \ | ||
67 | MASK_SYS_STATUS_URUN | \ | ||
68 | MASK_SYS_STATUS_ORUN | \ | ||
69 | MASK_SYS_STATUS_EOBO | \ | ||
70 | MASK_SYS_STATUS_EOBI | \ | ||
71 | MASK_SYS_STATUS_FREQ | \ | ||
72 | MASK_SYS_STATUS_ESA) | ||
73 | |||
74 | #define MASK_SYS_PCI_EVENTS (MASK_SYS_ASYNC_EVENTS | \ | ||
75 | MASK_SYS_STATUS_TIMER) | ||
76 | |||
77 | #define MASK_SYS_TIMER_COUNT 0x0000FFFF | ||
78 | |||
79 | #define MASK_SYS_STATUS_EOT_PLX (1L << 22) /* event that remains | ||
80 | * internal: reserved fo end | ||
81 | * of plx dma */ | ||
82 | #define MASK_SYS_STATUS_XES (1L << 21) /* event that remains | ||
83 | * internal: pending XES | ||
84 | * IRQ */ | ||
85 | #define MASK_SYS_STATUS_CMD_DONE (1L << 20) /* alternate command | ||
86 | * management: notify driver | ||
87 | * instead of polling */ | ||
88 | |||
89 | |||
90 | #define MAX_STREAM_BUFFER 5 /* max amount of stream buffers. */ | ||
91 | |||
92 | #define MICROBLAZE_IBL_MIN 32 | ||
93 | #define MICROBLAZE_IBL_DEFAULT 128 | ||
94 | #define MICROBLAZE_IBL_MAX 512 | ||
95 | /* #define MASK_GRANULARITY (2*MICROBLAZE_IBL_MAX-1) */ | ||
96 | |||
97 | |||
98 | |||
99 | /* command opcodes, see reference for details */ | ||
100 | |||
101 | /* | ||
102 | the capture bit position in the object_id field in driver commands | ||
103 | depends upon the number of managed channels. For now, 64 IN + 64 OUT are | ||
104 | supported. HOwever, the communication protocol forsees 1024 channels, hence | ||
105 | bit 10 indicates a capture (input) object). | ||
106 | */ | ||
107 | #define ID_IS_CAPTURE (1L << 10) | ||
108 | #define ID_OFFSET 13 /* object ID is at the 13th bit in the | ||
109 | * 1st command word.*/ | ||
110 | #define ID_CH_MASK 0x3F | ||
111 | #define OPCODE_OFFSET 24 /* offset of the command opcode in the first | ||
112 | * command word.*/ | ||
113 | |||
114 | enum cmd_mb_opcodes { | ||
115 | CMD_00_INFO_DEBUG = 0x00, | ||
116 | CMD_01_GET_SYS_CFG = 0x01, | ||
117 | CMD_02_SET_GRANULARITY = 0x02, | ||
118 | CMD_03_SET_TIMER_IRQ = 0x03, | ||
119 | CMD_04_GET_EVENT = 0x04, | ||
120 | CMD_05_GET_PIPES = 0x05, | ||
121 | |||
122 | CMD_06_ALLOCATE_PIPE = 0x06, | ||
123 | CMD_07_RELEASE_PIPE = 0x07, | ||
124 | CMD_08_ASK_BUFFERS = 0x08, | ||
125 | CMD_09_STOP_PIPE = 0x09, | ||
126 | CMD_0A_GET_PIPE_SPL_COUNT = 0x0a, | ||
127 | CMD_0B_TOGGLE_PIPE_STATE = 0x0b, | ||
128 | |||
129 | CMD_0C_DEF_STREAM = 0x0c, | ||
130 | CMD_0D_SET_MUTE = 0x0d, | ||
131 | CMD_0E_GET_STREAM_SPL_COUNT = 0x0e, | ||
132 | CMD_0F_UPDATE_BUFFER = 0x0f, | ||
133 | CMD_10_GET_BUFFER = 0x10, | ||
134 | CMD_11_CANCEL_BUFFER = 0x11, | ||
135 | CMD_12_GET_PEAK = 0x12, | ||
136 | CMD_13_SET_STREAM_STATE = 0x13, | ||
137 | CMD_14_INVALID = 0x14, | ||
138 | }; | ||
139 | |||
140 | /* pipe states */ | ||
141 | enum pipe_state_t { | ||
142 | PSTATE_IDLE = 0, /* the pipe is not processed in the XES_IRQ | ||
143 | * (free or stopped, or paused). */ | ||
144 | PSTATE_RUN = 1, /* sustained play/record state. */ | ||
145 | PSTATE_PURGE = 2, /* the ES channels are now off, render pipes do | ||
146 | * not DMA, record pipe do a last DMA. */ | ||
147 | PSTATE_ACQUIRE = 3, /* the ES channels are now on, render pipes do | ||
148 | * not yet increase their sample count, record | ||
149 | * pipes do not DMA. */ | ||
150 | PSTATE_CLOSING = 4, /* the pipe is releasing, and may not yet | ||
151 | * receive an "alloc" command. */ | ||
152 | }; | ||
153 | |||
154 | /* stream states */ | ||
155 | enum stream_state_t { | ||
156 | SSTATE_STOP = 0x00, /* setting to stop resets the stream spl | ||
157 | * count.*/ | ||
158 | SSTATE_RUN = (0x01 << 0), /* start DMA and spl count handling. */ | ||
159 | SSTATE_PAUSE = (0x01 << 1), /* pause DMA and spl count handling. */ | ||
160 | }; | ||
161 | |||
162 | /* buffer flags */ | ||
163 | enum buffer_flags { | ||
164 | BF_VALID = 0x80, /* set if the buffer is valid, clear if free.*/ | ||
165 | BF_CURRENT = 0x40, /* set if this is the current buffer (there is | ||
166 | * always a current buffer).*/ | ||
167 | BF_NOTIFY_EOB = 0x20, /* set if this buffer must cause a PCI event | ||
168 | * when finished.*/ | ||
169 | BF_CIRCULAR = 0x10, /* set if buffer[1] must be copied to buffer[0] | ||
170 | * by the end of this buffer.*/ | ||
171 | BF_64BITS_ADR = 0x08, /* set if the hi part of the address is valid.*/ | ||
172 | BF_xx = 0x04, /* future extension.*/ | ||
173 | BF_EOB = 0x02, /* set if finished, but not yet free.*/ | ||
174 | BF_PAUSE = 0x01, /* pause stream at buffer end.*/ | ||
175 | BF_ZERO = 0x00, /* no flags (init).*/ | ||
176 | }; | ||
177 | |||
178 | /** | ||
179 | * Stream Flags definitions | ||
180 | */ | ||
181 | enum stream_flags { | ||
182 | SF_ZERO = 0x00000000, /* no flags (stream invalid). */ | ||
183 | SF_VALID = 0x10000000, /* the stream has a valid DMA_conf | ||
184 | * info (setstreamformat). */ | ||
185 | SF_XRUN = 0x20000000, /* the stream is un x-run state. */ | ||
186 | SF_START = 0x40000000, /* the DMA is running.*/ | ||
187 | SF_ASIO = 0x80000000, /* ASIO.*/ | ||
188 | }; | ||
189 | |||
190 | |||
191 | #define MASK_SPL_COUNT_HI 0x00FFFFFF /* 4 MSBits are status bits */ | ||
192 | #define PSTATE_OFFSET 28 /* 4 MSBits are status bits */ | ||
193 | |||
194 | |||
195 | #define MASK_STREAM_HAS_MAPPING (1L << 12) | ||
196 | #define MASK_STREAM_IS_ASIO (1L << 9) | ||
197 | #define STREAM_FMT_OFFSET 10 /* the stream fmt bits start at the 10th | ||
198 | * bit in the command word. */ | ||
199 | |||
200 | #define STREAM_FMT_16b 0x02 | ||
201 | #define STREAM_FMT_intel 0x01 | ||
202 | |||
203 | #define FREQ_FIELD_OFFSET 15 /* offset of the freq field in the response | ||
204 | * word */ | ||
205 | |||
206 | #define BUFF_FLAGS_OFFSET 24 /* offset of the buffer flags in the | ||
207 | * response word. */ | ||
208 | #define MASK_DATA_SIZE 0x00FFFFFF /* this must match the field size of | ||
209 | * datasize in the buffer_t structure. */ | ||
210 | |||
211 | #define MASK_BUFFER_ID 0xFF /* the cancel command awaits a buffer ID, | ||
212 | * may be 0xFF for "current". */ | ||
213 | |||
214 | |||
215 | /* code adapted from PcxErr_e.h */ | ||
216 | |||
217 | /* Bits masks */ | ||
218 | |||
219 | #define ERROR_MASK 0x8000 | ||
220 | |||
221 | #define SOURCE_MASK 0x7800 | ||
222 | |||
223 | #define E_SOURCE_BOARD 0x4000 /* 8 >> 1 */ | ||
224 | #define E_SOURCE_DRV 0x2000 /* 4 >> 1 */ | ||
225 | #define E_SOURCE_API 0x1000 /* 2 >> 1 */ | ||
226 | /* Error tools */ | ||
227 | #define E_SOURCE_TOOLS 0x0800 /* 1 >> 1 */ | ||
228 | /* Error pcxaudio */ | ||
229 | #define E_SOURCE_AUDIO 0x1800 /* 3 >> 1 */ | ||
230 | /* Error virtual pcx */ | ||
231 | #define E_SOURCE_VPCX 0x2800 /* 5 >> 1 */ | ||
232 | /* Error dispatcher */ | ||
233 | #define E_SOURCE_DISPATCHER 0x3000 /* 6 >> 1 */ | ||
234 | /* Error from CobraNet firmware */ | ||
235 | #define E_SOURCE_COBRANET 0x3800 /* 7 >> 1 */ | ||
236 | |||
237 | #define E_SOURCE_USER 0x7800 | ||
238 | |||
239 | #define CLASS_MASK 0x0700 | ||
240 | |||
241 | #define CODE_MASK 0x00FF | ||
242 | |||
243 | /* Bits values */ | ||
244 | |||
245 | /* Values for the error/warning bit */ | ||
246 | #define ERROR_VALUE 0x8000 | ||
247 | #define WARNING_VALUE 0x0000 | ||
248 | |||
249 | /* Class values */ | ||
250 | #define E_CLASS_GENERAL 0x0000 | ||
251 | #define E_CLASS_INVALID_CMD 0x0100 | ||
252 | #define E_CLASS_INVALID_STD_OBJECT 0x0200 | ||
253 | #define E_CLASS_RSRC_IMPOSSIBLE 0x0300 | ||
254 | #define E_CLASS_WRONG_CONTEXT 0x0400 | ||
255 | #define E_CLASS_BAD_SPECIFIC_PARAMETER 0x0500 | ||
256 | #define E_CLASS_REAL_TIME_ERROR 0x0600 | ||
257 | #define E_CLASS_DIRECTSHOW 0x0700 | ||
258 | #define E_CLASS_FREE 0x0700 | ||
259 | |||
260 | |||
261 | /* Complete DRV error code for the general class */ | ||
262 | #define ED_GN (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_GENERAL) | ||
263 | #define ED_CONCURRENCY (ED_GN | 0x01) | ||
264 | #define ED_DSP_CRASHED (ED_GN | 0x02) | ||
265 | #define ED_UNKNOWN_BOARD (ED_GN | 0x03) | ||
266 | #define ED_NOT_INSTALLED (ED_GN | 0x04) | ||
267 | #define ED_CANNOT_OPEN_SVC_MANAGER (ED_GN | 0x05) | ||
268 | #define ED_CANNOT_READ_REGISTRY (ED_GN | 0x06) | ||
269 | #define ED_DSP_VERSION_MISMATCH (ED_GN | 0x07) | ||
270 | #define ED_UNAVAILABLE_FEATURE (ED_GN | 0x08) | ||
271 | #define ED_CANCELLED (ED_GN | 0x09) | ||
272 | #define ED_NO_RESPONSE_AT_IRQA (ED_GN | 0x10) | ||
273 | #define ED_INVALID_ADDRESS (ED_GN | 0x11) | ||
274 | #define ED_DSP_CORRUPTED (ED_GN | 0x12) | ||
275 | #define ED_PENDING_OPERATION (ED_GN | 0x13) | ||
276 | #define ED_NET_ALLOCATE_MEMORY_IMPOSSIBLE (ED_GN | 0x14) | ||
277 | #define ED_NET_REGISTER_ERROR (ED_GN | 0x15) | ||
278 | #define ED_NET_THREAD_ERROR (ED_GN | 0x16) | ||
279 | #define ED_NET_OPEN_ERROR (ED_GN | 0x17) | ||
280 | #define ED_NET_CLOSE_ERROR (ED_GN | 0x18) | ||
281 | #define ED_NET_NO_MORE_PACKET (ED_GN | 0x19) | ||
282 | #define ED_NET_NO_MORE_BUFFER (ED_GN | 0x1A) | ||
283 | #define ED_NET_SEND_ERROR (ED_GN | 0x1B) | ||
284 | #define ED_NET_RECEIVE_ERROR (ED_GN | 0x1C) | ||
285 | #define ED_NET_WRONG_MSG_SIZE (ED_GN | 0x1D) | ||
286 | #define ED_NET_WAIT_ERROR (ED_GN | 0x1E) | ||
287 | #define ED_NET_EEPROM_ERROR (ED_GN | 0x1F) | ||
288 | #define ED_INVALID_RS232_COM_NUMBER (ED_GN | 0x20) | ||
289 | #define ED_INVALID_RS232_INIT (ED_GN | 0x21) | ||
290 | #define ED_FILE_ERROR (ED_GN | 0x22) | ||
291 | #define ED_INVALID_GPIO_CMD (ED_GN | 0x23) | ||
292 | #define ED_RS232_ALREADY_OPENED (ED_GN | 0x24) | ||
293 | #define ED_RS232_NOT_OPENED (ED_GN | 0x25) | ||
294 | #define ED_GPIO_ALREADY_OPENED (ED_GN | 0x26) | ||
295 | #define ED_GPIO_NOT_OPENED (ED_GN | 0x27) | ||
296 | #define ED_REGISTRY_ERROR (ED_GN | 0x28) /* <- NCX */ | ||
297 | #define ED_INVALID_SERVICE (ED_GN | 0x29) /* <- NCX */ | ||
298 | |||
299 | #define ED_READ_FILE_ALREADY_OPENED (ED_GN | 0x2a) /* <- Decalage | ||
300 | * pour RCX | ||
301 | * (old 0x28) | ||
302 | * */ | ||
303 | #define ED_READ_FILE_INVALID_COMMAND (ED_GN | 0x2b) /* ~ */ | ||
304 | #define ED_READ_FILE_INVALID_PARAMETER (ED_GN | 0x2c) /* ~ */ | ||
305 | #define ED_READ_FILE_ALREADY_CLOSED (ED_GN | 0x2d) /* ~ */ | ||
306 | #define ED_READ_FILE_NO_INFORMATION (ED_GN | 0x2e) /* ~ */ | ||
307 | #define ED_READ_FILE_INVALID_HANDLE (ED_GN | 0x2f) /* ~ */ | ||
308 | #define ED_READ_FILE_END_OF_FILE (ED_GN | 0x30) /* ~ */ | ||
309 | #define ED_READ_FILE_ERROR (ED_GN | 0x31) /* ~ */ | ||
310 | |||
311 | #define ED_DSP_CRASHED_EXC_DSPSTACK_OVERFLOW (ED_GN | 0x32) /* <- Decalage pour | ||
312 | * PCX (old 0x14) */ | ||
313 | #define ED_DSP_CRASHED_EXC_SYSSTACK_OVERFLOW (ED_GN | 0x33) /* ~ */ | ||
314 | #define ED_DSP_CRASHED_EXC_ILLEGAL (ED_GN | 0x34) /* ~ */ | ||
315 | #define ED_DSP_CRASHED_EXC_TIMER_REENTRY (ED_GN | 0x35) /* ~ */ | ||
316 | #define ED_DSP_CRASHED_EXC_FATAL_ERROR (ED_GN | 0x36) /* ~ */ | ||
317 | |||
318 | #define ED_FLASH_PCCARD_NOT_PRESENT (ED_GN | 0x37) | ||
319 | |||
320 | #define ED_NO_CURRENT_CLOCK (ED_GN | 0x38) | ||
321 | |||
322 | /* Complete DRV error code for real time class */ | ||
323 | #define ED_RT (ERROR_VALUE | E_SOURCE_DRV | E_CLASS_REAL_TIME_ERROR) | ||
324 | #define ED_DSP_TIMED_OUT (ED_RT | 0x01) | ||
325 | #define ED_DSP_CHK_TIMED_OUT (ED_RT | 0x02) | ||
326 | #define ED_STREAM_OVERRUN (ED_RT | 0x03) | ||
327 | #define ED_DSP_BUSY (ED_RT | 0x04) | ||
328 | #define ED_DSP_SEMAPHORE_TIME_OUT (ED_RT | 0x05) | ||
329 | #define ED_BOARD_TIME_OUT (ED_RT | 0x06) | ||
330 | #define ED_XILINX_ERROR (ED_RT | 0x07) | ||
331 | #define ED_COBRANET_ITF_NOT_RESPONDING (ED_RT | 0x08) | ||
332 | |||
333 | /* Complete BOARD error code for the invaid standard object class */ | ||
334 | #define EB_ISO (ERROR_VALUE | E_SOURCE_BOARD | \ | ||
335 | E_CLASS_INVALID_STD_OBJECT) | ||
336 | #define EB_INVALID_EFFECT (EB_ISO | 0x00) | ||
337 | #define EB_INVALID_PIPE (EB_ISO | 0x40) | ||
338 | #define EB_INVALID_STREAM (EB_ISO | 0x80) | ||
339 | #define EB_INVALID_AUDIO (EB_ISO | 0xC0) | ||
340 | |||
341 | /* Complete BOARD error code for impossible resource allocation class */ | ||
342 | #define EB_RI (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_RSRC_IMPOSSIBLE) | ||
343 | #define EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE (EB_RI | 0x01) | ||
344 | #define EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE (EB_RI | 0x02) | ||
345 | |||
346 | #define EB_ALLOCATE_MEM_STREAM_IMPOSSIBLE \ | ||
347 | EB_ALLOCATE_ALL_STREAM_TRANSFERT_BUFFERS_IMPOSSIBLE | ||
348 | #define EB_ALLOCATE_MEM_PIPE_IMPOSSIBLE \ | ||
349 | EB_ALLOCATE_PIPE_SAMPLE_BUFFER_IMPOSSIBLE | ||
350 | |||
351 | #define EB_ALLOCATE_DIFFERED_CMD_IMPOSSIBLE (EB_RI | 0x03) | ||
352 | #define EB_TOO_MANY_DIFFERED_CMD (EB_RI | 0x04) | ||
353 | #define EB_RBUFFERS_TABLE_OVERFLOW (EB_RI | 0x05) | ||
354 | #define EB_ALLOCATE_EFFECTS_IMPOSSIBLE (EB_RI | 0x08) | ||
355 | #define EB_ALLOCATE_EFFECT_POS_IMPOSSIBLE (EB_RI | 0x09) | ||
356 | #define EB_RBUFFER_NOT_AVAILABLE (EB_RI | 0x0A) | ||
357 | #define EB_ALLOCATE_CONTEXT_LIII_IMPOSSIBLE (EB_RI | 0x0B) | ||
358 | #define EB_STATUS_DIALOG_IMPOSSIBLE (EB_RI | 0x1D) | ||
359 | #define EB_CONTROL_CMD_IMPOSSIBLE (EB_RI | 0x1E) | ||
360 | #define EB_STATUS_SEND_IMPOSSIBLE (EB_RI | 0x1F) | ||
361 | #define EB_ALLOCATE_PIPE_IMPOSSIBLE (EB_RI | 0x40) | ||
362 | #define EB_ALLOCATE_STREAM_IMPOSSIBLE (EB_RI | 0x80) | ||
363 | #define EB_ALLOCATE_AUDIO_IMPOSSIBLE (EB_RI | 0xC0) | ||
364 | |||
365 | /* Complete BOARD error code for wrong call context class */ | ||
366 | #define EB_WCC (ERROR_VALUE | E_SOURCE_BOARD | E_CLASS_WRONG_CONTEXT) | ||
367 | #define EB_CMD_REFUSED (EB_WCC | 0x00) | ||
368 | #define EB_START_STREAM_REFUSED (EB_WCC | 0xFC) | ||
369 | #define EB_SPC_REFUSED (EB_WCC | 0xFD) | ||
370 | #define EB_CSN_REFUSED (EB_WCC | 0xFE) | ||
371 | #define EB_CSE_REFUSED (EB_WCC | 0xFF) | ||
372 | |||
373 | |||
374 | |||
375 | |||
376 | #endif /* LX_DEFS_H */ | ||
diff --git a/sound/pci/oxygen/oxygen_pcm.c b/sound/pci/oxygen/oxygen_pcm.c index c262049961e1..3b5ca70c9d4d 100644 --- a/sound/pci/oxygen/oxygen_pcm.c +++ b/sound/pci/oxygen/oxygen_pcm.c | |||
@@ -487,10 +487,14 @@ static int oxygen_hw_free(struct snd_pcm_substream *substream) | |||
487 | { | 487 | { |
488 | struct oxygen *chip = snd_pcm_substream_chip(substream); | 488 | struct oxygen *chip = snd_pcm_substream_chip(substream); |
489 | unsigned int channel = oxygen_substream_channel(substream); | 489 | unsigned int channel = oxygen_substream_channel(substream); |
490 | unsigned int channel_mask = 1 << channel; | ||
490 | 491 | ||
491 | spin_lock_irq(&chip->reg_lock); | 492 | spin_lock_irq(&chip->reg_lock); |
492 | chip->interrupt_mask &= ~(1 << channel); | 493 | chip->interrupt_mask &= ~channel_mask; |
493 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); | 494 | oxygen_write16(chip, OXYGEN_INTERRUPT_MASK, chip->interrupt_mask); |
495 | |||
496 | oxygen_set_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | ||
497 | oxygen_clear_bits8(chip, OXYGEN_DMA_FLUSH, channel_mask); | ||
494 | spin_unlock_irq(&chip->reg_lock); | 498 | spin_unlock_irq(&chip->reg_lock); |
495 | 499 | ||
496 | return snd_pcm_lib_free_pages(substream); | 500 | return snd_pcm_lib_free_pages(substream); |
diff --git a/sound/pci/oxygen/virtuoso.c b/sound/pci/oxygen/virtuoso.c index bc5ce11c8b14..bf971f7cfdc6 100644 --- a/sound/pci/oxygen/virtuoso.c +++ b/sound/pci/oxygen/virtuoso.c | |||
@@ -113,8 +113,8 @@ | |||
113 | */ | 113 | */ |
114 | 114 | ||
115 | /* | 115 | /* |
116 | * Xonar Essence STX | 116 | * Xonar Essence ST (Deluxe)/STX |
117 | * ----------------- | 117 | * ----------------------------- |
118 | * | 118 | * |
119 | * CMI8788: | 119 | * CMI8788: |
120 | * | 120 | * |
@@ -180,6 +180,8 @@ enum { | |||
180 | MODEL_DX, | 180 | MODEL_DX, |
181 | MODEL_HDAV, /* without daughterboard */ | 181 | MODEL_HDAV, /* without daughterboard */ |
182 | MODEL_HDAV_H6, /* with H6 daughterboard */ | 182 | MODEL_HDAV_H6, /* with H6 daughterboard */ |
183 | MODEL_ST, | ||
184 | MODEL_ST_H6, | ||
183 | MODEL_STX, | 185 | MODEL_STX, |
184 | }; | 186 | }; |
185 | 187 | ||
@@ -188,8 +190,10 @@ static struct pci_device_id xonar_ids[] __devinitdata = { | |||
188 | { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX }, | 190 | { OXYGEN_PCI_SUBID(0x1043, 0x8275), .driver_data = MODEL_DX }, |
189 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, | 191 | { OXYGEN_PCI_SUBID(0x1043, 0x82b7), .driver_data = MODEL_D2X }, |
190 | { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, | 192 | { OXYGEN_PCI_SUBID(0x1043, 0x8314), .driver_data = MODEL_HDAV }, |
193 | { OXYGEN_PCI_SUBID(0x1043, 0x8327), .driver_data = MODEL_DX }, | ||
191 | { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, | 194 | { OXYGEN_PCI_SUBID(0x1043, 0x834f), .driver_data = MODEL_D1 }, |
192 | { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX }, | 195 | { OXYGEN_PCI_SUBID(0x1043, 0x835c), .driver_data = MODEL_STX }, |
196 | { OXYGEN_PCI_SUBID(0x1043, 0x835d), .driver_data = MODEL_ST }, | ||
193 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, | 197 | { OXYGEN_PCI_SUBID_BROKEN_EEPROM }, |
194 | { } | 198 | { } |
195 | }; | 199 | }; |
@@ -210,9 +214,9 @@ MODULE_DEVICE_TABLE(pci, xonar_ids); | |||
210 | #define GPIO_DX_FRONT_PANEL 0x0002 | 214 | #define GPIO_DX_FRONT_PANEL 0x0002 |
211 | #define GPIO_DX_INPUT_ROUTE 0x0100 | 215 | #define GPIO_DX_INPUT_ROUTE 0x0100 |
212 | 216 | ||
213 | #define GPIO_HDAV_DB_MASK 0x0030 | 217 | #define GPIO_DB_MASK 0x0030 |
214 | #define GPIO_HDAV_DB_H6 0x0000 | 218 | #define GPIO_DB_H6 0x0000 |
215 | #define GPIO_HDAV_DB_XX 0x0020 | 219 | #define GPIO_DB_XX 0x0020 |
216 | 220 | ||
217 | #define GPIO_ST_HP_REAR 0x0002 | 221 | #define GPIO_ST_HP_REAR 0x0002 |
218 | #define GPIO_ST_HP 0x0080 | 222 | #define GPIO_ST_HP 0x0080 |
@@ -530,7 +534,7 @@ static void xonar_hdav_init(struct oxygen *chip) | |||
530 | snd_component_add(chip->card, "CS5381"); | 534 | snd_component_add(chip->card, "CS5381"); |
531 | } | 535 | } |
532 | 536 | ||
533 | static void xonar_stx_init(struct oxygen *chip) | 537 | static void xonar_st_init(struct oxygen *chip) |
534 | { | 538 | { |
535 | struct xonar_data *data = chip->model_data; | 539 | struct xonar_data *data = chip->model_data; |
536 | 540 | ||
@@ -539,12 +543,11 @@ static void xonar_stx_init(struct oxygen *chip) | |||
539 | OXYGEN_2WIRE_INTERRUPT_MASK | | 543 | OXYGEN_2WIRE_INTERRUPT_MASK | |
540 | OXYGEN_2WIRE_SPEED_FAST); | 544 | OXYGEN_2WIRE_SPEED_FAST); |
541 | 545 | ||
546 | if (chip->model.private_data == MODEL_ST_H6) | ||
547 | chip->model.dac_channels = 8; | ||
542 | data->anti_pop_delay = 100; | 548 | data->anti_pop_delay = 100; |
543 | data->dacs = 1; | 549 | data->dacs = chip->model.private_data == MODEL_ST_H6 ? 4 : 1; |
544 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; | 550 | data->output_enable_bit = GPIO_DX_OUTPUT_ENABLE; |
545 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
546 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
547 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
548 | data->pcm1796_oversampling = PCM1796_OS_64; | 551 | data->pcm1796_oversampling = PCM1796_OS_64; |
549 | 552 | ||
550 | pcm1796_init(chip); | 553 | pcm1796_init(chip); |
@@ -560,6 +563,17 @@ static void xonar_stx_init(struct oxygen *chip) | |||
560 | snd_component_add(chip->card, "CS5381"); | 563 | snd_component_add(chip->card, "CS5381"); |
561 | } | 564 | } |
562 | 565 | ||
566 | static void xonar_stx_init(struct oxygen *chip) | ||
567 | { | ||
568 | struct xonar_data *data = chip->model_data; | ||
569 | |||
570 | data->ext_power_reg = OXYGEN_GPI_DATA; | ||
571 | data->ext_power_int_reg = OXYGEN_GPI_INTERRUPT_MASK; | ||
572 | data->ext_power_bit = GPI_DX_EXT_POWER; | ||
573 | |||
574 | xonar_st_init(chip); | ||
575 | } | ||
576 | |||
563 | static void xonar_disable_output(struct oxygen *chip) | 577 | static void xonar_disable_output(struct oxygen *chip) |
564 | { | 578 | { |
565 | struct xonar_data *data = chip->model_data; | 579 | struct xonar_data *data = chip->model_data; |
@@ -1021,7 +1035,8 @@ static const struct oxygen_model model_xonar_hdav = { | |||
1021 | .model_data_size = sizeof(struct xonar_data), | 1035 | .model_data_size = sizeof(struct xonar_data), |
1022 | .device_config = PLAYBACK_0_TO_I2S | | 1036 | .device_config = PLAYBACK_0_TO_I2S | |
1023 | PLAYBACK_1_TO_SPDIF | | 1037 | PLAYBACK_1_TO_SPDIF | |
1024 | CAPTURE_0_FROM_I2S_2, | 1038 | CAPTURE_0_FROM_I2S_2 | |
1039 | CAPTURE_1_FROM_SPDIF, | ||
1025 | .dac_channels = 8, | 1040 | .dac_channels = 8, |
1026 | .dac_volume_min = 255 - 2*60, | 1041 | .dac_volume_min = 255 - 2*60, |
1027 | .dac_volume_max = 255, | 1042 | .dac_volume_max = 255, |
@@ -1034,7 +1049,7 @@ static const struct oxygen_model model_xonar_hdav = { | |||
1034 | static const struct oxygen_model model_xonar_st = { | 1049 | static const struct oxygen_model model_xonar_st = { |
1035 | .longname = "Asus Virtuoso 100", | 1050 | .longname = "Asus Virtuoso 100", |
1036 | .chip = "AV200", | 1051 | .chip = "AV200", |
1037 | .init = xonar_stx_init, | 1052 | .init = xonar_st_init, |
1038 | .control_filter = xonar_st_control_filter, | 1053 | .control_filter = xonar_st_control_filter, |
1039 | .mixer_init = xonar_st_mixer_init, | 1054 | .mixer_init = xonar_st_mixer_init, |
1040 | .cleanup = xonar_st_cleanup, | 1055 | .cleanup = xonar_st_cleanup, |
@@ -1067,6 +1082,7 @@ static int __devinit get_xonar_model(struct oxygen *chip, | |||
1067 | [MODEL_D2] = &model_xonar_d2, | 1082 | [MODEL_D2] = &model_xonar_d2, |
1068 | [MODEL_D2X] = &model_xonar_d2, | 1083 | [MODEL_D2X] = &model_xonar_d2, |
1069 | [MODEL_HDAV] = &model_xonar_hdav, | 1084 | [MODEL_HDAV] = &model_xonar_hdav, |
1085 | [MODEL_ST] = &model_xonar_st, | ||
1070 | [MODEL_STX] = &model_xonar_st, | 1086 | [MODEL_STX] = &model_xonar_st, |
1071 | }; | 1087 | }; |
1072 | static const char *const names[] = { | 1088 | static const char *const names[] = { |
@@ -1076,6 +1092,8 @@ static int __devinit get_xonar_model(struct oxygen *chip, | |||
1076 | [MODEL_D2X] = "Xonar D2X", | 1092 | [MODEL_D2X] = "Xonar D2X", |
1077 | [MODEL_HDAV] = "Xonar HDAV1.3", | 1093 | [MODEL_HDAV] = "Xonar HDAV1.3", |
1078 | [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", | 1094 | [MODEL_HDAV_H6] = "Xonar HDAV1.3+H6", |
1095 | [MODEL_ST] = "Xonar Essence ST", | ||
1096 | [MODEL_ST_H6] = "Xonar Essence ST+H6", | ||
1079 | [MODEL_STX] = "Xonar Essence STX", | 1097 | [MODEL_STX] = "Xonar Essence STX", |
1080 | }; | 1098 | }; |
1081 | unsigned int model = id->driver_data; | 1099 | unsigned int model = id->driver_data; |
@@ -1092,21 +1110,27 @@ static int __devinit get_xonar_model(struct oxygen *chip, | |||
1092 | chip->model.init = xonar_dx_init; | 1110 | chip->model.init = xonar_dx_init; |
1093 | break; | 1111 | break; |
1094 | case MODEL_HDAV: | 1112 | case MODEL_HDAV: |
1095 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | 1113 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); |
1096 | GPIO_HDAV_DB_MASK); | 1114 | switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { |
1097 | switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & | 1115 | case GPIO_DB_H6: |
1098 | GPIO_HDAV_DB_MASK) { | ||
1099 | case GPIO_HDAV_DB_H6: | ||
1100 | model = MODEL_HDAV_H6; | 1116 | model = MODEL_HDAV_H6; |
1101 | break; | 1117 | break; |
1102 | case GPIO_HDAV_DB_XX: | 1118 | case GPIO_DB_XX: |
1103 | snd_printk(KERN_ERR "unknown daughterboard\n"); | 1119 | snd_printk(KERN_ERR "unknown daughterboard\n"); |
1104 | return -ENODEV; | 1120 | return -ENODEV; |
1105 | } | 1121 | } |
1106 | break; | 1122 | break; |
1123 | case MODEL_ST: | ||
1124 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); | ||
1125 | switch (oxygen_read16(chip, OXYGEN_GPIO_DATA) & GPIO_DB_MASK) { | ||
1126 | case GPIO_DB_H6: | ||
1127 | model = MODEL_ST_H6; | ||
1128 | break; | ||
1129 | } | ||
1130 | break; | ||
1107 | case MODEL_STX: | 1131 | case MODEL_STX: |
1108 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, | 1132 | chip->model.init = xonar_stx_init; |
1109 | GPIO_HDAV_DB_MASK); | 1133 | oxygen_clear_bits16(chip, OXYGEN_GPIO_CONTROL, GPIO_DB_MASK); |
1110 | break; | 1134 | break; |
1111 | } | 1135 | } |
1112 | 1136 | ||
diff --git a/sound/pci/riptide/riptide.c b/sound/pci/riptide/riptide.c index 6f1034417a02..235a71e5ac8d 100644 --- a/sound/pci/riptide/riptide.c +++ b/sound/pci/riptide/riptide.c | |||
@@ -507,41 +507,19 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip); | |||
507 | */ | 507 | */ |
508 | 508 | ||
509 | static struct pci_device_id snd_riptide_ids[] = { | 509 | static struct pci_device_id snd_riptide_ids[] = { |
510 | { | 510 | { PCI_DEVICE(0x127a, 0x4310) }, |
511 | .vendor = 0x127a,.device = 0x4310, | 511 | { PCI_DEVICE(0x127a, 0x4320) }, |
512 | .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, | 512 | { PCI_DEVICE(0x127a, 0x4330) }, |
513 | }, | 513 | { PCI_DEVICE(0x127a, 0x4340) }, |
514 | { | ||
515 | .vendor = 0x127a,.device = 0x4320, | ||
516 | .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, | ||
517 | }, | ||
518 | { | ||
519 | .vendor = 0x127a,.device = 0x4330, | ||
520 | .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, | ||
521 | }, | ||
522 | { | ||
523 | .vendor = 0x127a,.device = 0x4340, | ||
524 | .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, | ||
525 | }, | ||
526 | {0,}, | 514 | {0,}, |
527 | }; | 515 | }; |
528 | 516 | ||
529 | #ifdef SUPPORT_JOYSTICK | 517 | #ifdef SUPPORT_JOYSTICK |
530 | static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = { | 518 | static struct pci_device_id snd_riptide_joystick_ids[] __devinitdata = { |
531 | { | 519 | { PCI_DEVICE(0x127a, 0x4312) }, |
532 | .vendor = 0x127a,.device = 0x4312, | 520 | { PCI_DEVICE(0x127a, 0x4322) }, |
533 | .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, | 521 | { PCI_DEVICE(0x127a, 0x4332) }, |
534 | }, | 522 | { PCI_DEVICE(0x127a, 0x4342) }, |
535 | { | ||
536 | .vendor = 0x127a,.device = 0x4322, | ||
537 | .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, | ||
538 | }, | ||
539 | {.vendor = 0x127a,.device = 0x4332, | ||
540 | .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, | ||
541 | }, | ||
542 | {.vendor = 0x127a,.device = 0x4342, | ||
543 | .subvendor = PCI_ANY_ID,.subdevice = PCI_ANY_ID, | ||
544 | }, | ||
545 | {0,}, | 523 | {0,}, |
546 | }; | 524 | }; |
547 | #endif | 525 | #endif |
@@ -889,7 +867,7 @@ static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm, | |||
889 | spin_lock_irqsave(&cif->lock, irqflags); | 867 | spin_lock_irqsave(&cif->lock, irqflags); |
890 | while (i++ < CMDIF_TIMEOUT && !IS_READY(cif->hwport)) | 868 | while (i++ < CMDIF_TIMEOUT && !IS_READY(cif->hwport)) |
891 | udelay(10); | 869 | udelay(10); |
892 | if (i >= CMDIF_TIMEOUT) { | 870 | if (i > CMDIF_TIMEOUT) { |
893 | err = -EBUSY; | 871 | err = -EBUSY; |
894 | goto errout; | 872 | goto errout; |
895 | } | 873 | } |
@@ -907,8 +885,10 @@ static int sendcmd(struct cmdif *cif, u32 flags, u32 cmd, u32 parm, | |||
907 | WRITE_PORT_ULONG(cmdport->data1, cmd); /* write cmd */ | 885 | WRITE_PORT_ULONG(cmdport->data1, cmd); /* write cmd */ |
908 | if ((flags & RESP) && ret) { | 886 | if ((flags & RESP) && ret) { |
909 | while (!IS_DATF(cmdport) && | 887 | while (!IS_DATF(cmdport) && |
910 | time++ < CMDIF_TIMEOUT) | 888 | time < CMDIF_TIMEOUT) { |
911 | udelay(10); | 889 | udelay(10); |
890 | time++; | ||
891 | } | ||
912 | if (time < CMDIF_TIMEOUT) { /* read response */ | 892 | if (time < CMDIF_TIMEOUT) { /* read response */ |
913 | ret->retlongs[0] = | 893 | ret->retlongs[0] = |
914 | READ_PORT_ULONG(cmdport->data1); | 894 | READ_PORT_ULONG(cmdport->data1); |
@@ -1207,12 +1187,79 @@ static int riptide_resume(struct pci_dev *pci) | |||
1207 | } | 1187 | } |
1208 | #endif | 1188 | #endif |
1209 | 1189 | ||
1190 | static int try_to_load_firmware(struct cmdif *cif, struct snd_riptide *chip) | ||
1191 | { | ||
1192 | union firmware_version firmware = { .ret = CMDRET_ZERO }; | ||
1193 | int i, timeout, err; | ||
1194 | |||
1195 | for (i = 0; i < 2; i++) { | ||
1196 | WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0); | ||
1197 | WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0); | ||
1198 | } | ||
1199 | SET_GRESET(cif->hwport); | ||
1200 | udelay(100); | ||
1201 | UNSET_GRESET(cif->hwport); | ||
1202 | udelay(100); | ||
1203 | |||
1204 | for (timeout = 100000; --timeout; udelay(10)) { | ||
1205 | if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport)) | ||
1206 | break; | ||
1207 | } | ||
1208 | if (!timeout) { | ||
1209 | snd_printk(KERN_ERR | ||
1210 | "Riptide: device not ready, audio status: 0x%x " | ||
1211 | "ready: %d gerr: %d\n", | ||
1212 | READ_AUDIO_STATUS(cif->hwport), | ||
1213 | IS_READY(cif->hwport), IS_GERR(cif->hwport)); | ||
1214 | return -EIO; | ||
1215 | } else { | ||
1216 | snd_printdd | ||
1217 | ("Riptide: audio status: 0x%x ready: %d gerr: %d\n", | ||
1218 | READ_AUDIO_STATUS(cif->hwport), | ||
1219 | IS_READY(cif->hwport), IS_GERR(cif->hwport)); | ||
1220 | } | ||
1221 | |||
1222 | SEND_GETV(cif, &firmware.ret); | ||
1223 | snd_printdd("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", | ||
1224 | firmware.firmware.ASIC, firmware.firmware.CODEC, | ||
1225 | firmware.firmware.AUXDSP, firmware.firmware.PROG); | ||
1226 | |||
1227 | for (i = 0; i < FIRMWARE_VERSIONS; i++) { | ||
1228 | if (!memcmp(&firmware_versions[i], &firmware, sizeof(firmware))) | ||
1229 | break; | ||
1230 | } | ||
1231 | if (i >= FIRMWARE_VERSIONS) | ||
1232 | return 0; /* no match */ | ||
1233 | |||
1234 | if (!chip) | ||
1235 | return 1; /* OK */ | ||
1236 | |||
1237 | snd_printdd("Writing Firmware\n"); | ||
1238 | if (!chip->fw_entry) { | ||
1239 | err = request_firmware(&chip->fw_entry, "riptide.hex", | ||
1240 | &chip->pci->dev); | ||
1241 | if (err) { | ||
1242 | snd_printk(KERN_ERR | ||
1243 | "Riptide: Firmware not available %d\n", err); | ||
1244 | return -EIO; | ||
1245 | } | ||
1246 | } | ||
1247 | err = loadfirmware(cif, chip->fw_entry->data, chip->fw_entry->size); | ||
1248 | if (err) { | ||
1249 | snd_printk(KERN_ERR | ||
1250 | "Riptide: Could not load firmware %d\n", err); | ||
1251 | return err; | ||
1252 | } | ||
1253 | |||
1254 | chip->firmware = firmware; | ||
1255 | |||
1256 | return 1; /* OK */ | ||
1257 | } | ||
1258 | |||
1210 | static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) | 1259 | static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) |
1211 | { | 1260 | { |
1212 | int timeout, tries; | ||
1213 | union cmdret rptr = CMDRET_ZERO; | 1261 | union cmdret rptr = CMDRET_ZERO; |
1214 | union firmware_version firmware; | 1262 | int err, tries; |
1215 | int i, j, err, has_firmware; | ||
1216 | 1263 | ||
1217 | if (!cif) | 1264 | if (!cif) |
1218 | return -EINVAL; | 1265 | return -EINVAL; |
@@ -1225,75 +1272,11 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) | |||
1225 | cif->is_reset = 0; | 1272 | cif->is_reset = 0; |
1226 | 1273 | ||
1227 | tries = RESET_TRIES; | 1274 | tries = RESET_TRIES; |
1228 | has_firmware = 0; | 1275 | do { |
1229 | while (has_firmware == 0 && tries-- > 0) { | 1276 | err = try_to_load_firmware(cif, chip); |
1230 | for (i = 0; i < 2; i++) { | 1277 | if (err < 0) |
1231 | WRITE_PORT_ULONG(cif->hwport->port[i].data1, 0); | 1278 | return err; |
1232 | WRITE_PORT_ULONG(cif->hwport->port[i].data2, 0); | 1279 | } while (!err && --tries); |
1233 | } | ||
1234 | SET_GRESET(cif->hwport); | ||
1235 | udelay(100); | ||
1236 | UNSET_GRESET(cif->hwport); | ||
1237 | udelay(100); | ||
1238 | |||
1239 | for (timeout = 100000; --timeout; udelay(10)) { | ||
1240 | if (IS_READY(cif->hwport) && !IS_GERR(cif->hwport)) | ||
1241 | break; | ||
1242 | } | ||
1243 | if (timeout == 0) { | ||
1244 | snd_printk(KERN_ERR | ||
1245 | "Riptide: device not ready, audio status: 0x%x ready: %d gerr: %d\n", | ||
1246 | READ_AUDIO_STATUS(cif->hwport), | ||
1247 | IS_READY(cif->hwport), IS_GERR(cif->hwport)); | ||
1248 | return -EIO; | ||
1249 | } else { | ||
1250 | snd_printdd | ||
1251 | ("Riptide: audio status: 0x%x ready: %d gerr: %d\n", | ||
1252 | READ_AUDIO_STATUS(cif->hwport), | ||
1253 | IS_READY(cif->hwport), IS_GERR(cif->hwport)); | ||
1254 | } | ||
1255 | |||
1256 | SEND_GETV(cif, &rptr); | ||
1257 | for (i = 0; i < 4; i++) | ||
1258 | firmware.ret.retwords[i] = rptr.retwords[i]; | ||
1259 | |||
1260 | snd_printdd | ||
1261 | ("Firmware version: ASIC: %d CODEC %d AUXDSP %d PROG %d\n", | ||
1262 | firmware.firmware.ASIC, firmware.firmware.CODEC, | ||
1263 | firmware.firmware.AUXDSP, firmware.firmware.PROG); | ||
1264 | |||
1265 | for (j = 0; j < FIRMWARE_VERSIONS; j++) { | ||
1266 | has_firmware = 1; | ||
1267 | for (i = 0; i < 4; i++) { | ||
1268 | if (firmware_versions[j].ret.retwords[i] != | ||
1269 | firmware.ret.retwords[i]) | ||
1270 | has_firmware = 0; | ||
1271 | } | ||
1272 | if (has_firmware) | ||
1273 | break; | ||
1274 | } | ||
1275 | |||
1276 | if (chip != NULL && has_firmware == 0) { | ||
1277 | snd_printdd("Writing Firmware\n"); | ||
1278 | if (!chip->fw_entry) { | ||
1279 | if ((err = | ||
1280 | request_firmware(&chip->fw_entry, | ||
1281 | "riptide.hex", | ||
1282 | &chip->pci->dev)) != 0) { | ||
1283 | snd_printk(KERN_ERR | ||
1284 | "Riptide: Firmware not available %d\n", | ||
1285 | err); | ||
1286 | return -EIO; | ||
1287 | } | ||
1288 | } | ||
1289 | err = loadfirmware(cif, chip->fw_entry->data, | ||
1290 | chip->fw_entry->size); | ||
1291 | if (err) | ||
1292 | snd_printk(KERN_ERR | ||
1293 | "Riptide: Could not load firmware %d\n", | ||
1294 | err); | ||
1295 | } | ||
1296 | } | ||
1297 | 1280 | ||
1298 | SEND_SACR(cif, 0, AC97_RESET); | 1281 | SEND_SACR(cif, 0, AC97_RESET); |
1299 | SEND_RACR(cif, AC97_RESET, &rptr); | 1282 | SEND_RACR(cif, AC97_RESET, &rptr); |
@@ -1335,11 +1318,6 @@ static int riptide_reset(struct cmdif *cif, struct snd_riptide *chip) | |||
1335 | SET_AIE(cif->hwport); | 1318 | SET_AIE(cif->hwport); |
1336 | SET_AIACK(cif->hwport); | 1319 | SET_AIACK(cif->hwport); |
1337 | cif->is_reset = 1; | 1320 | cif->is_reset = 1; |
1338 | if (chip) { | ||
1339 | for (i = 0; i < 4; i++) | ||
1340 | chip->firmware.ret.retwords[i] = | ||
1341 | firmware.ret.retwords[i]; | ||
1342 | } | ||
1343 | 1321 | ||
1344 | return 0; | 1322 | return 0; |
1345 | } | 1323 | } |
@@ -1454,7 +1432,7 @@ static int snd_riptide_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1454 | SEND_GPOS(cif, 0, data->id, &rptr); | 1432 | SEND_GPOS(cif, 0, data->id, &rptr); |
1455 | udelay(1); | 1433 | udelay(1); |
1456 | } while (i != rptr.retlongs[1] && j++ < MAX_WRITE_RETRY); | 1434 | } while (i != rptr.retlongs[1] && j++ < MAX_WRITE_RETRY); |
1457 | if (j >= MAX_WRITE_RETRY) | 1435 | if (j > MAX_WRITE_RETRY) |
1458 | snd_printk(KERN_ERR "Riptide: Could not stop stream!"); | 1436 | snd_printk(KERN_ERR "Riptide: Could not stop stream!"); |
1459 | break; | 1437 | break; |
1460 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1438 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
@@ -1783,7 +1761,7 @@ snd_riptide_codec_write(struct snd_ac97 *ac97, unsigned short reg, | |||
1783 | SEND_SACR(cif, val, reg); | 1761 | SEND_SACR(cif, val, reg); |
1784 | SEND_RACR(cif, reg, &rptr); | 1762 | SEND_RACR(cif, reg, &rptr); |
1785 | } while (rptr.retwords[1] != val && i++ < MAX_WRITE_RETRY); | 1763 | } while (rptr.retwords[1] != val && i++ < MAX_WRITE_RETRY); |
1786 | if (i == MAX_WRITE_RETRY) | 1764 | if (i > MAX_WRITE_RETRY) |
1787 | snd_printdd("Write AC97 reg failed\n"); | 1765 | snd_printdd("Write AC97 reg failed\n"); |
1788 | } | 1766 | } |
1789 | 1767 | ||
@@ -2036,14 +2014,12 @@ static int __devinit snd_riptide_mixer(struct snd_riptide *chip) | |||
2036 | } | 2014 | } |
2037 | 2015 | ||
2038 | #ifdef SUPPORT_JOYSTICK | 2016 | #ifdef SUPPORT_JOYSTICK |
2039 | static int have_joystick; | ||
2040 | static struct pci_dev *riptide_gameport_pci; | ||
2041 | static struct gameport *riptide_gameport; | ||
2042 | 2017 | ||
2043 | static int __devinit | 2018 | static int __devinit |
2044 | snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) | 2019 | snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) |
2045 | { | 2020 | { |
2046 | static int dev; | 2021 | static int dev; |
2022 | struct gameport *gameport; | ||
2047 | 2023 | ||
2048 | if (dev >= SNDRV_CARDS) | 2024 | if (dev >= SNDRV_CARDS) |
2049 | return -ENODEV; | 2025 | return -ENODEV; |
@@ -2052,36 +2028,33 @@ snd_riptide_joystick_probe(struct pci_dev *pci, const struct pci_device_id *id) | |||
2052 | return -ENOENT; | 2028 | return -ENOENT; |
2053 | } | 2029 | } |
2054 | 2030 | ||
2055 | if (joystick_port[dev]) { | 2031 | if (!joystick_port[dev++]) |
2056 | riptide_gameport = gameport_allocate_port(); | 2032 | return 0; |
2057 | if (riptide_gameport) { | 2033 | |
2058 | if (!request_region | 2034 | gameport = gameport_allocate_port(); |
2059 | (joystick_port[dev], 8, "Riptide gameport")) { | 2035 | if (!gameport) |
2060 | snd_printk(KERN_WARNING | 2036 | return -ENOMEM; |
2061 | "Riptide: cannot grab gameport 0x%x\n", | 2037 | if (!request_region(joystick_port[dev], 8, "Riptide gameport")) { |
2062 | joystick_port[dev]); | 2038 | snd_printk(KERN_WARNING |
2063 | gameport_free_port(riptide_gameport); | 2039 | "Riptide: cannot grab gameport 0x%x\n", |
2064 | riptide_gameport = NULL; | 2040 | joystick_port[dev]); |
2065 | } else { | 2041 | gameport_free_port(gameport); |
2066 | riptide_gameport_pci = pci; | 2042 | return -EBUSY; |
2067 | riptide_gameport->io = joystick_port[dev]; | ||
2068 | gameport_register_port(riptide_gameport); | ||
2069 | } | ||
2070 | } | ||
2071 | } | 2043 | } |
2072 | dev++; | 2044 | |
2045 | gameport->io = joystick_port[dev]; | ||
2046 | gameport_register_port(gameport); | ||
2047 | pci_set_drvdata(pci, gameport); | ||
2073 | return 0; | 2048 | return 0; |
2074 | } | 2049 | } |
2075 | 2050 | ||
2076 | static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci) | 2051 | static void __devexit snd_riptide_joystick_remove(struct pci_dev *pci) |
2077 | { | 2052 | { |
2078 | if (riptide_gameport) { | 2053 | struct gameport *gameport = pci_get_drvdata(pci); |
2079 | if (riptide_gameport_pci == pci) { | 2054 | if (gameport) { |
2080 | release_region(riptide_gameport->io, 8); | 2055 | release_region(gameport->io, 8); |
2081 | riptide_gameport_pci = NULL; | 2056 | gameport_unregister_port(gameport); |
2082 | gameport_unregister_port(riptide_gameport); | 2057 | pci_set_drvdata(pci, NULL); |
2083 | riptide_gameport = NULL; | ||
2084 | } | ||
2085 | } | 2058 | } |
2086 | } | 2059 | } |
2087 | #endif | 2060 | #endif |
@@ -2092,8 +2065,8 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
2092 | static int dev; | 2065 | static int dev; |
2093 | struct snd_card *card; | 2066 | struct snd_card *card; |
2094 | struct snd_riptide *chip; | 2067 | struct snd_riptide *chip; |
2095 | unsigned short addr; | 2068 | unsigned short val; |
2096 | int err = 0; | 2069 | int err; |
2097 | 2070 | ||
2098 | if (dev >= SNDRV_CARDS) | 2071 | if (dev >= SNDRV_CARDS) |
2099 | return -ENODEV; | 2072 | return -ENODEV; |
@@ -2105,60 +2078,63 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
2105 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); | 2078 | err = snd_card_create(index[dev], id[dev], THIS_MODULE, 0, &card); |
2106 | if (err < 0) | 2079 | if (err < 0) |
2107 | return err; | 2080 | return err; |
2108 | if ((err = snd_riptide_create(card, pci, &chip)) < 0) { | 2081 | err = snd_riptide_create(card, pci, &chip); |
2109 | snd_card_free(card); | 2082 | if (err < 0) |
2110 | return err; | 2083 | goto error; |
2111 | } | ||
2112 | card->private_data = chip; | 2084 | card->private_data = chip; |
2113 | if ((err = snd_riptide_pcm(chip, 0, NULL)) < 0) { | 2085 | err = snd_riptide_pcm(chip, 0, NULL); |
2114 | snd_card_free(card); | 2086 | if (err < 0) |
2115 | return err; | 2087 | goto error; |
2116 | } | 2088 | err = snd_riptide_mixer(chip); |
2117 | if ((err = snd_riptide_mixer(chip)) < 0) { | 2089 | if (err < 0) |
2118 | snd_card_free(card); | 2090 | goto error; |
2119 | return err; | 2091 | |
2120 | } | 2092 | val = LEGACY_ENABLE_ALL; |
2121 | pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, LEGACY_ENABLE_ALL | 2093 | if (opl3_port[dev]) |
2122 | | (opl3_port[dev] ? LEGACY_ENABLE_FM : 0) | 2094 | val |= LEGACY_ENABLE_FM; |
2123 | #ifdef SUPPORT_JOYSTICK | 2095 | #ifdef SUPPORT_JOYSTICK |
2124 | | (joystick_port[dev] ? LEGACY_ENABLE_GAMEPORT : | 2096 | if (joystick_port[dev]) |
2125 | 0) | 2097 | val |= LEGACY_ENABLE_GAMEPORT; |
2126 | #endif | 2098 | #endif |
2127 | | (mpu_port[dev] | 2099 | if (mpu_port[dev]) |
2128 | ? (LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU) : | 2100 | val |= LEGACY_ENABLE_MPU_INT | LEGACY_ENABLE_MPU; |
2129 | 0) | 2101 | val |= (chip->irq << 4) & 0xf0; |
2130 | | ((chip->irq << 4) & 0xF0)); | 2102 | pci_write_config_word(chip->pci, PCI_EXT_Legacy_Mask, val); |
2131 | if ((addr = mpu_port[dev]) != 0) { | 2103 | if (mpu_port[dev]) { |
2132 | pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, addr); | 2104 | val = mpu_port[dev]; |
2133 | if ((err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE, | 2105 | pci_write_config_word(chip->pci, PCI_EXT_MPU_Base, val); |
2134 | addr, 0, chip->irq, 0, | 2106 | err = snd_mpu401_uart_new(card, 0, MPU401_HW_RIPTIDE, |
2135 | &chip->rmidi)) < 0) | 2107 | val, 0, chip->irq, 0, |
2108 | &chip->rmidi); | ||
2109 | if (err < 0) | ||
2136 | snd_printk(KERN_WARNING | 2110 | snd_printk(KERN_WARNING |
2137 | "Riptide: Can't Allocate MPU at 0x%x\n", | 2111 | "Riptide: Can't Allocate MPU at 0x%x\n", |
2138 | addr); | 2112 | val); |
2139 | else | 2113 | else |
2140 | chip->mpuaddr = addr; | 2114 | chip->mpuaddr = val; |
2141 | } | 2115 | } |
2142 | if ((addr = opl3_port[dev]) != 0) { | 2116 | if (opl3_port[dev]) { |
2143 | pci_write_config_word(chip->pci, PCI_EXT_FM_Base, addr); | 2117 | val = opl3_port[dev]; |
2144 | if ((err = snd_opl3_create(card, addr, addr + 2, | 2118 | pci_write_config_word(chip->pci, PCI_EXT_FM_Base, val); |
2145 | OPL3_HW_RIPTIDE, 0, | 2119 | err = snd_opl3_create(card, val, val + 2, |
2146 | &chip->opl3)) < 0) | 2120 | OPL3_HW_RIPTIDE, 0, &chip->opl3); |
2121 | if (err < 0) | ||
2147 | snd_printk(KERN_WARNING | 2122 | snd_printk(KERN_WARNING |
2148 | "Riptide: Can't Allocate OPL3 at 0x%x\n", | 2123 | "Riptide: Can't Allocate OPL3 at 0x%x\n", |
2149 | addr); | 2124 | val); |
2150 | else { | 2125 | else { |
2151 | chip->opladdr = addr; | 2126 | chip->opladdr = val; |
2152 | if ((err = | 2127 | err = snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL); |
2153 | snd_opl3_hwdep_new(chip->opl3, 0, 1, NULL)) < 0) | 2128 | if (err < 0) |
2154 | snd_printk(KERN_WARNING | 2129 | snd_printk(KERN_WARNING |
2155 | "Riptide: Can't Allocate OPL3-HWDEP\n"); | 2130 | "Riptide: Can't Allocate OPL3-HWDEP\n"); |
2156 | } | 2131 | } |
2157 | } | 2132 | } |
2158 | #ifdef SUPPORT_JOYSTICK | 2133 | #ifdef SUPPORT_JOYSTICK |
2159 | if ((addr = joystick_port[dev]) != 0) { | 2134 | if (joystick_port[dev]) { |
2160 | pci_write_config_word(chip->pci, PCI_EXT_Game_Base, addr); | 2135 | val = joystick_port[dev]; |
2161 | chip->gameaddr = addr; | 2136 | pci_write_config_word(chip->pci, PCI_EXT_Game_Base, val); |
2137 | chip->gameaddr = val; | ||
2162 | } | 2138 | } |
2163 | #endif | 2139 | #endif |
2164 | 2140 | ||
@@ -2176,13 +2152,16 @@ snd_card_riptide_probe(struct pci_dev *pci, const struct pci_device_id *pci_id) | |||
2176 | chip->opladdr); | 2152 | chip->opladdr); |
2177 | #endif | 2153 | #endif |
2178 | snd_riptide_proc_init(chip); | 2154 | snd_riptide_proc_init(chip); |
2179 | if ((err = snd_card_register(card)) < 0) { | 2155 | err = snd_card_register(card); |
2180 | snd_card_free(card); | 2156 | if (err < 0) |
2181 | return err; | 2157 | goto error; |
2182 | } | ||
2183 | pci_set_drvdata(pci, card); | 2158 | pci_set_drvdata(pci, card); |
2184 | dev++; | 2159 | dev++; |
2185 | return 0; | 2160 | return 0; |
2161 | |||
2162 | error: | ||
2163 | snd_card_free(card); | ||
2164 | return err; | ||
2186 | } | 2165 | } |
2187 | 2166 | ||
2188 | static void __devexit snd_card_riptide_remove(struct pci_dev *pci) | 2167 | static void __devexit snd_card_riptide_remove(struct pci_dev *pci) |
@@ -2214,14 +2193,11 @@ static struct pci_driver joystick_driver = { | |||
2214 | static int __init alsa_card_riptide_init(void) | 2193 | static int __init alsa_card_riptide_init(void) |
2215 | { | 2194 | { |
2216 | int err; | 2195 | int err; |
2217 | if ((err = pci_register_driver(&driver)) < 0) | 2196 | err = pci_register_driver(&driver); |
2197 | if (err < 0) | ||
2218 | return err; | 2198 | return err; |
2219 | #if defined(SUPPORT_JOYSTICK) | 2199 | #if defined(SUPPORT_JOYSTICK) |
2220 | if (pci_register_driver(&joystick_driver) < 0) { | 2200 | pci_register_driver(&joystick_driver); |
2221 | have_joystick = 0; | ||
2222 | snd_printk(KERN_INFO "no joystick found\n"); | ||
2223 | } else | ||
2224 | have_joystick = 1; | ||
2225 | #endif | 2201 | #endif |
2226 | return 0; | 2202 | return 0; |
2227 | } | 2203 | } |
@@ -2230,8 +2206,7 @@ static void __exit alsa_card_riptide_exit(void) | |||
2230 | { | 2206 | { |
2231 | pci_unregister_driver(&driver); | 2207 | pci_unregister_driver(&driver); |
2232 | #if defined(SUPPORT_JOYSTICK) | 2208 | #if defined(SUPPORT_JOYSTICK) |
2233 | if (have_joystick) | 2209 | pci_unregister_driver(&joystick_driver); |
2234 | pci_unregister_driver(&joystick_driver); | ||
2235 | #endif | 2210 | #endif |
2236 | } | 2211 | } |
2237 | 2212 | ||
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c index 314e73531bd1..3da5c029f93b 100644 --- a/sound/pci/rme9652/hdsp.c +++ b/sound/pci/rme9652/hdsp.c | |||
@@ -28,6 +28,7 @@ | |||
28 | #include <linux/pci.h> | 28 | #include <linux/pci.h> |
29 | #include <linux/firmware.h> | 29 | #include <linux/firmware.h> |
30 | #include <linux/moduleparam.h> | 30 | #include <linux/moduleparam.h> |
31 | #include <linux/math64.h> | ||
31 | 32 | ||
32 | #include <sound/core.h> | 33 | #include <sound/core.h> |
33 | #include <sound/control.h> | 34 | #include <sound/control.h> |
@@ -402,9 +403,9 @@ MODULE_FIRMWARE("digiface_firmware_rev11.bin"); | |||
402 | #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) | 403 | #define HDSP_DMA_AREA_BYTES ((HDSP_MAX_CHANNELS+1) * HDSP_CHANNEL_BUFFER_BYTES) |
403 | #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) | 404 | #define HDSP_DMA_AREA_KILOBYTES (HDSP_DMA_AREA_BYTES/1024) |
404 | 405 | ||
405 | /* use hotplug firmeare loader? */ | 406 | /* use hotplug firmware loader? */ |
406 | #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) | 407 | #if defined(CONFIG_FW_LOADER) || defined(CONFIG_FW_LOADER_MODULE) |
407 | #if !defined(HDSP_USE_HWDEP_LOADER) && !defined(CONFIG_SND_HDSP) | 408 | #if !defined(HDSP_USE_HWDEP_LOADER) |
408 | #define HDSP_FW_LOADER | 409 | #define HDSP_FW_LOADER |
409 | #endif | 410 | #endif |
410 | #endif | 411 | #endif |
@@ -1047,7 +1048,6 @@ static int hdsp_set_interrupt_interval(struct hdsp *s, unsigned int frames) | |||
1047 | static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) | 1048 | static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) |
1048 | { | 1049 | { |
1049 | u64 n; | 1050 | u64 n; |
1050 | u32 r; | ||
1051 | 1051 | ||
1052 | if (rate >= 112000) | 1052 | if (rate >= 112000) |
1053 | rate /= 4; | 1053 | rate /= 4; |
@@ -1055,7 +1055,7 @@ static void hdsp_set_dds_value(struct hdsp *hdsp, int rate) | |||
1055 | rate /= 2; | 1055 | rate /= 2; |
1056 | 1056 | ||
1057 | n = DDS_NUMERATOR; | 1057 | n = DDS_NUMERATOR; |
1058 | div64_32(&n, rate, &r); | 1058 | n = div_u64(n, rate); |
1059 | /* n should be less than 2^32 for being written to FREQ register */ | 1059 | /* n should be less than 2^32 for being written to FREQ register */ |
1060 | snd_BUG_ON(n >> 32); | 1060 | snd_BUG_ON(n >> 32); |
1061 | /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS | 1061 | /* HDSP_freqReg and HDSP_resetPointer are the same, so keep the DDS |
@@ -3097,7 +3097,6 @@ static int snd_hdsp_get_adat_sync_check(struct snd_kcontrol *kcontrol, struct sn | |||
3097 | static int hdsp_dds_offset(struct hdsp *hdsp) | 3097 | static int hdsp_dds_offset(struct hdsp *hdsp) |
3098 | { | 3098 | { |
3099 | u64 n; | 3099 | u64 n; |
3100 | u32 r; | ||
3101 | unsigned int dds_value = hdsp->dds_value; | 3100 | unsigned int dds_value = hdsp->dds_value; |
3102 | int system_sample_rate = hdsp->system_sample_rate; | 3101 | int system_sample_rate = hdsp->system_sample_rate; |
3103 | 3102 | ||
@@ -3109,7 +3108,7 @@ static int hdsp_dds_offset(struct hdsp *hdsp) | |||
3109 | * dds_value = n / rate | 3108 | * dds_value = n / rate |
3110 | * rate = n / dds_value | 3109 | * rate = n / dds_value |
3111 | */ | 3110 | */ |
3112 | div64_32(&n, dds_value, &r); | 3111 | n = div_u64(n, dds_value); |
3113 | if (system_sample_rate >= 112000) | 3112 | if (system_sample_rate >= 112000) |
3114 | n *= 4; | 3113 | n *= 4; |
3115 | else if (system_sample_rate >= 56000) | 3114 | else if (system_sample_rate >= 56000) |
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c index bac2dc0c5d85..0dce331a2a3b 100644 --- a/sound/pci/rme9652/hdspm.c +++ b/sound/pci/rme9652/hdspm.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/moduleparam.h> | 29 | #include <linux/moduleparam.h> |
30 | #include <linux/slab.h> | 30 | #include <linux/slab.h> |
31 | #include <linux/pci.h> | 31 | #include <linux/pci.h> |
32 | #include <linux/math64.h> | ||
32 | #include <asm/io.h> | 33 | #include <asm/io.h> |
33 | 34 | ||
34 | #include <sound/core.h> | 35 | #include <sound/core.h> |
@@ -831,7 +832,6 @@ static int hdspm_set_interrupt_interval(struct hdspm * s, unsigned int frames) | |||
831 | static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) | 832 | static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) |
832 | { | 833 | { |
833 | u64 n; | 834 | u64 n; |
834 | u32 r; | ||
835 | 835 | ||
836 | if (rate >= 112000) | 836 | if (rate >= 112000) |
837 | rate /= 4; | 837 | rate /= 4; |
@@ -844,7 +844,7 @@ static void hdspm_set_dds_value(struct hdspm *hdspm, int rate) | |||
844 | */ | 844 | */ |
845 | /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */ | 845 | /* n = 104857600000000ULL; */ /* = 2^20 * 10^8 */ |
846 | n = 110100480000000ULL; /* Value checked for AES32 and MADI */ | 846 | n = 110100480000000ULL; /* Value checked for AES32 and MADI */ |
847 | div64_32(&n, rate, &r); | 847 | n = div_u64(n, rate); |
848 | /* n should be less than 2^32 for being written to FREQ register */ | 848 | /* n should be less than 2^32 for being written to FREQ register */ |
849 | snd_BUG_ON(n >> 32); | 849 | snd_BUG_ON(n >> 32); |
850 | hdspm_write(hdspm, HDSPM_freqReg, (u32)n); | 850 | hdspm_write(hdspm, HDSPM_freqReg, (u32)n); |
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c index 809b233dd4a3..1ef58c51c213 100644 --- a/sound/pci/via82xx.c +++ b/sound/pci/via82xx.c | |||
@@ -1687,7 +1687,7 @@ static int snd_via8233_pcmdxs_volume_put(struct snd_kcontrol *kcontrol, | |||
1687 | return change; | 1687 | return change; |
1688 | } | 1688 | } |
1689 | 1689 | ||
1690 | static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -9450, 150, 1); | 1690 | static const DECLARE_TLV_DB_SCALE(db_scale_dxs, -4650, 150, 1); |
1691 | 1691 | ||
1692 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { | 1692 | static struct snd_kcontrol_new snd_via8233_pcmdxs_volume_control __devinitdata = { |
1693 | .name = "PCM Playback Volume", | 1693 | .name = "PCM Playback Volume", |