diff options
author | James Courtier-Dutton <James@superbug.co.uk> | 2006-12-06 10:58:02 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@suse.cz> | 2007-02-09 03:02:17 -0500 |
commit | 184c1e2c4c4221c2b8d1e16c33314595373fa73f (patch) | |
tree | f041f147ba8c92e5587163d0b76863fdf4f0318b /sound | |
parent | 9ed1261e3e617d99b0eb74041d0337ff664e4f5b (diff) |
[ALSA] emu10k1: Add Audio capture support for Audigy 2 ZS Notebook.
Implement functionallity in order to fixe ALSA bug#2058.
Signed-off-by: James Courtier-Dutton <James@superbug.co.uk>
Signed-off-by: Jaroslav Kysela <perex@suse.cz>
Diffstat (limited to 'sound')
-rw-r--r-- | sound/pci/emu10k1/emu10k1_main.c | 70 | ||||
-rw-r--r-- | sound/pci/emu10k1/emumixer.c | 201 | ||||
-rw-r--r-- | sound/pci/emu10k1/io.c | 59 | ||||
-rw-r--r-- | sound/pci/emu10k1/p17v.h | 47 |
4 files changed, 370 insertions, 7 deletions
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c index 711e819e4a0b..80aa585eade4 100644 --- a/sound/pci/emu10k1/emu10k1_main.c +++ b/sound/pci/emu10k1/emu10k1_main.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/firmware.h> | 46 | #include <linux/firmware.h> |
47 | #include "p16v.h" | 47 | #include "p16v.h" |
48 | #include "tina2.h" | 48 | #include "tina2.h" |
49 | #include "p17v.h" | ||
49 | 50 | ||
50 | 51 | ||
51 | /************************************************************************* | 52 | /************************************************************************* |
@@ -120,11 +121,28 @@ static unsigned int spi_dac_init[] = { | |||
120 | 0x0622, | 121 | 0x0622, |
121 | 0x1400, | 122 | 0x1400, |
122 | }; | 123 | }; |
124 | |||
125 | static unsigned int i2c_adc_init[][2] = { | ||
126 | { 0x17, 0x00 }, /* Reset */ | ||
127 | { 0x07, 0x00 }, /* Timeout */ | ||
128 | { 0x0b, 0x22 }, /* Interface control */ | ||
129 | { 0x0c, 0x22 }, /* Master mode control */ | ||
130 | { 0x0d, 0x08 }, /* Powerdown control */ | ||
131 | { 0x0e, 0xcf }, /* Attenuation Left 0x01 = -103dB, 0xff = 24dB */ | ||
132 | { 0x0f, 0xcf }, /* Attenuation Right 0.5dB steps */ | ||
133 | { 0x10, 0x7b }, /* ALC Control 1 */ | ||
134 | { 0x11, 0x00 }, /* ALC Control 2 */ | ||
135 | { 0x12, 0x32 }, /* ALC Control 3 */ | ||
136 | { 0x13, 0x00 }, /* Noise gate control */ | ||
137 | { 0x14, 0xa6 }, /* Limiter control */ | ||
138 | { 0x15, ADC_MUX_2 }, /* ADC Mixer control. Mic for Audigy 2 ZS Notebook */ | ||
139 | }; | ||
123 | 140 | ||
124 | static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | 141 | static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) |
125 | { | 142 | { |
126 | unsigned int silent_page; | 143 | unsigned int silent_page; |
127 | int ch; | 144 | int ch; |
145 | u32 tmp; | ||
128 | 146 | ||
129 | /* disable audio and lock cache */ | 147 | /* disable audio and lock cache */ |
130 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, | 148 | outl(HCFG_LOCKSOUNDCACHE | HCFG_LOCKTANKCACHE_MASK | HCFG_MUTEBUTTONENABLE, |
@@ -163,8 +181,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
163 | 181 | ||
164 | if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ | 182 | if (emu->card_capabilities->ca0151_chip) { /* audigy2 */ |
165 | /* Hacks for Alice3 to work independent of haP16V driver */ | 183 | /* Hacks for Alice3 to work independent of haP16V driver */ |
166 | u32 tmp; | ||
167 | |||
168 | //Setup SRCMulti_I2S SamplingRate | 184 | //Setup SRCMulti_I2S SamplingRate |
169 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | 185 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); |
170 | tmp &= 0xfffff1ff; | 186 | tmp &= 0xfffff1ff; |
@@ -184,8 +200,6 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
184 | } | 200 | } |
185 | if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ | 201 | if (emu->card_capabilities->ca0108_chip) { /* audigy2 Value */ |
186 | /* Hacks for Alice3 to work independent of haP16V driver */ | 202 | /* Hacks for Alice3 to work independent of haP16V driver */ |
187 | u32 tmp; | ||
188 | |||
189 | snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); | 203 | snd_printk(KERN_INFO "Audigy2 value: Special config.\n"); |
190 | //Setup SRCMulti_I2S SamplingRate | 204 | //Setup SRCMulti_I2S SamplingRate |
191 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); | 205 | tmp = snd_emu10k1_ptr_read(emu, A_SPDIF_SAMPLERATE, 0); |
@@ -231,6 +245,23 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
231 | outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ | 245 | outl(0x76, emu->port + A_IOCFG); /* Windows uses 0x3f76 */ |
232 | 246 | ||
233 | } | 247 | } |
248 | if (emu->card_capabilities->i2c_adc) { /* Audigy 2 ZS Notebook with ADC Wolfson WM8775 */ | ||
249 | int size, n; | ||
250 | |||
251 | snd_emu10k1_ptr20_write(emu, P17V_I2S_SRC_SEL, 0, 0x2020205f); | ||
252 | tmp = inl(emu->port + A_IOCFG); | ||
253 | outl(tmp | 0x4, emu->port + A_IOCFG); /* Set bit 2 for mic input */ | ||
254 | tmp = inl(emu->port + A_IOCFG); | ||
255 | size = ARRAY_SIZE(i2c_adc_init); | ||
256 | for (n = 0; n < size; n++) | ||
257 | snd_emu10k1_i2c_write(emu, i2c_adc_init[n][0], i2c_adc_init[n][1]); | ||
258 | for (n=0; n < 4; n++) { | ||
259 | emu->i2c_capture_volume[n][0]= 0xcf; | ||
260 | emu->i2c_capture_volume[n][1]= 0xcf; | ||
261 | } | ||
262 | |||
263 | } | ||
264 | |||
234 | 265 | ||
235 | snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); | 266 | snd_emu10k1_ptr_write(emu, PTB, 0, emu->ptb_pages.addr); |
236 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ | 267 | snd_emu10k1_ptr_write(emu, TCB, 0, 0); /* taken from original driver */ |
@@ -274,6 +305,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
274 | if (enable_ir) { /* enable IR for SB Live */ | 305 | if (enable_ir) { /* enable IR for SB Live */ |
275 | if (emu->card_capabilities->emu1010) { | 306 | if (emu->card_capabilities->emu1010) { |
276 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 307 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
308 | } else if (emu->card_capabilities->i2c_adc) { | ||
309 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | ||
277 | } else if (emu->audigy) { | 310 | } else if (emu->audigy) { |
278 | unsigned int reg = inl(emu->port + A_IOCFG); | 311 | unsigned int reg = inl(emu->port + A_IOCFG); |
279 | outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); | 312 | outl(reg | A_IOCFG_GPOUT2, emu->port + A_IOCFG); |
@@ -293,6 +326,8 @@ static int snd_emu10k1_init(struct snd_emu10k1 *emu, int enable_ir, int resume) | |||
293 | 326 | ||
294 | if (emu->card_capabilities->emu1010) { | 327 | if (emu->card_capabilities->emu1010) { |
295 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 328 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
329 | } else if (emu->card_capabilities->i2c_adc) { | ||
330 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | ||
296 | } else if (emu->audigy) { /* enable analog output */ | 331 | } else if (emu->audigy) { /* enable analog output */ |
297 | unsigned int reg = inl(emu->port + A_IOCFG); | 332 | unsigned int reg = inl(emu->port + A_IOCFG); |
298 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); | 333 | outl(reg | A_IOCFG_GPOUT0, emu->port + A_IOCFG); |
@@ -311,6 +346,8 @@ static void snd_emu10k1_audio_enable(struct snd_emu10k1 *emu) | |||
311 | /* Enable analog/digital outs on audigy */ | 346 | /* Enable analog/digital outs on audigy */ |
312 | if (emu->card_capabilities->emu1010) { | 347 | if (emu->card_capabilities->emu1010) { |
313 | ; /* Disable all access to A_IOCFG for the emu1010 */ | 348 | ; /* Disable all access to A_IOCFG for the emu1010 */ |
349 | } else if (emu->card_capabilities->i2c_adc) { | ||
350 | ; /* Disable A_IOCFG for Audigy 2 ZS Notebook */ | ||
314 | } else if (emu->audigy) { | 351 | } else if (emu->audigy) { |
315 | outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); | 352 | outl(inl(emu->port + A_IOCFG) & ~0x44, emu->port + A_IOCFG); |
316 | 353 | ||
@@ -1139,10 +1176,11 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1139 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ | 1176 | .adc_1361t = 1, /* 24 bit capture instead of 16bit */ |
1140 | .ac97_chip = 1} , | 1177 | .ac97_chip = 1} , |
1141 | /* Audigy 2 ZS Notebook Cardbus card.*/ | 1178 | /* Audigy 2 ZS Notebook Cardbus card.*/ |
1142 | /* Tested by James@superbug.co.uk 22th December 2005 */ | 1179 | /* Tested by James@superbug.co.uk 6th November 2006 */ |
1143 | /* Audio output 7.1/Headphones working. | 1180 | /* Audio output 7.1/Headphones working. |
1144 | * Digital output working. (AC3 not checked, only PCM) | 1181 | * Digital output working. (AC3 not checked, only PCM) |
1145 | * Audio inputs not tested. | 1182 | * Audio Mic/Line inputs working. |
1183 | * Digital input not tested. | ||
1146 | */ | 1184 | */ |
1147 | /* DSP: Tina2 | 1185 | /* DSP: Tina2 |
1148 | * DAC: Wolfson WM8768/WM8568 | 1186 | * DAC: Wolfson WM8768/WM8568 |
@@ -1150,6 +1188,25 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1150 | * AC97: None | 1188 | * AC97: None |
1151 | * CA0151: None | 1189 | * CA0151: None |
1152 | */ | 1190 | */ |
1191 | /* Tested by James@superbug.co.uk 4th April 2006 */ | ||
1192 | /* A_IOCFG bits | ||
1193 | * Output | ||
1194 | * 0: Not Used | ||
1195 | * 1: 0 = Mute all the 7.1 channel out. 1 = unmute. | ||
1196 | * 2: Analog input 0 = line in, 1 = mic in | ||
1197 | * 3: Not Used | ||
1198 | * 4: Digital output 0 = off, 1 = on. | ||
1199 | * 5: Not Used | ||
1200 | * 6: Not Used | ||
1201 | * 7: Not Used | ||
1202 | * Input | ||
1203 | * All bits 1 (0x3fxx) means nothing plugged in. | ||
1204 | * 8-9: 0 = Line in/Mic, 2 = Optical in, 3 = Nothing. | ||
1205 | * A-B: 0 = Headphones, 2 = Optical out, 3 = Nothing. | ||
1206 | * C-D: 2 = Front/Rear/etc, 3 = nothing. | ||
1207 | * E-F: Always 0 | ||
1208 | * | ||
1209 | */ | ||
1153 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, | 1210 | {.vendor = 0x1102, .device = 0x0008, .subsystem = 0x20011102, |
1154 | .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", | 1211 | .driver = "Audigy2", .name = "Audigy 2 ZS Notebook [SB0530]", |
1155 | .id = "Audigy2", | 1212 | .id = "Audigy2", |
@@ -1157,6 +1214,7 @@ static struct snd_emu_chip_details emu_chip_details[] = { | |||
1157 | .ca0108_chip = 1, | 1214 | .ca0108_chip = 1, |
1158 | .ca_cardbus_chip = 1, | 1215 | .ca_cardbus_chip = 1, |
1159 | .spi_dac = 1, | 1216 | .spi_dac = 1, |
1217 | .i2c_adc = 1, | ||
1160 | .spk71 = 1} , | 1218 | .spk71 = 1} , |
1161 | {.vendor = 0x1102, .device = 0x0008, | 1219 | {.vendor = 0x1102, .device = 0x0008, |
1162 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", | 1220 | .driver = "Audigy2", .name = "Audigy 2 Value [Unknown]", |
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c index 9b7fd564343e..b8221f385ff9 100644 --- a/sound/pci/emu10k1/emumixer.c +++ b/sound/pci/emu10k1/emumixer.c | |||
@@ -36,9 +36,14 @@ | |||
36 | #include <sound/core.h> | 36 | #include <sound/core.h> |
37 | #include <sound/emu10k1.h> | 37 | #include <sound/emu10k1.h> |
38 | #include <linux/delay.h> | 38 | #include <linux/delay.h> |
39 | #include <sound/tlv.h> | ||
40 | |||
41 | #include "p17v.h" | ||
39 | 42 | ||
40 | #define AC97_ID_STAC9758 0x83847658 | 43 | #define AC97_ID_STAC9758 0x83847658 |
41 | 44 | ||
45 | static DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */ | ||
46 | |||
42 | static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 47 | static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
43 | { | 48 | { |
44 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; | 49 | uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; |
@@ -579,6 +584,162 @@ static struct snd_kcontrol_new snd_emu1010_internal_clock = | |||
579 | .put = snd_emu1010_internal_clock_put | 584 | .put = snd_emu1010_internal_clock_put |
580 | }; | 585 | }; |
581 | 586 | ||
587 | static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol, | ||
588 | struct snd_ctl_elem_info *uinfo) | ||
589 | { | ||
590 | #if 0 | ||
591 | static char *texts[4] = { | ||
592 | "Unknown1", "Unknown2", "Mic", "Line" | ||
593 | }; | ||
594 | #endif | ||
595 | static char *texts[2] = { | ||
596 | "Mic", "Line" | ||
597 | }; | ||
598 | |||
599 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
600 | uinfo->count = 1; | ||
601 | uinfo->value.enumerated.items = 2; | ||
602 | if (uinfo->value.enumerated.item > 1) | ||
603 | uinfo->value.enumerated.item = 1; | ||
604 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
605 | return 0; | ||
606 | } | ||
607 | |||
608 | static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol, | ||
609 | struct snd_ctl_elem_value *ucontrol) | ||
610 | { | ||
611 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
612 | |||
613 | ucontrol->value.enumerated.item[0] = emu->i2c_capture_source; | ||
614 | return 0; | ||
615 | } | ||
616 | |||
617 | static int snd_audigy_i2c_capture_source_put(struct snd_kcontrol *kcontrol, | ||
618 | struct snd_ctl_elem_value *ucontrol) | ||
619 | { | ||
620 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
621 | unsigned int source_id; | ||
622 | unsigned int ngain, ogain; | ||
623 | u32 gpio; | ||
624 | int change = 0; | ||
625 | unsigned long flags; | ||
626 | u32 source; | ||
627 | /* If the capture source has changed, | ||
628 | * update the capture volume from the cached value | ||
629 | * for the particular source. | ||
630 | */ | ||
631 | source_id = ucontrol->value.enumerated.item[0]; /* Use 2 and 3 */ | ||
632 | change = (emu->i2c_capture_source != source_id); | ||
633 | if (change) { | ||
634 | snd_emu10k1_i2c_write(emu, ADC_MUX, 0); /* Mute input */ | ||
635 | spin_lock_irqsave(&emu->emu_lock, flags); | ||
636 | gpio = inl(emu->port + A_IOCFG); | ||
637 | if (source_id==0) | ||
638 | outl(gpio | 0x4, emu->port + A_IOCFG); | ||
639 | else | ||
640 | outl(gpio & ~0x4, emu->port + A_IOCFG); | ||
641 | spin_unlock_irqrestore(&emu->emu_lock, flags); | ||
642 | |||
643 | ngain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
644 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][0]; /* Left */ | ||
645 | if (ngain != ogain) | ||
646 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff)); | ||
647 | ngain = emu->i2c_capture_volume[source_id][1]; /* Right */ | ||
648 | ogain = emu->i2c_capture_volume[emu->i2c_capture_source][1]; /* Right */ | ||
649 | if (ngain != ogain) | ||
650 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
651 | |||
652 | source = 1 << (source_id + 2); | ||
653 | snd_emu10k1_i2c_write(emu, ADC_MUX, source); /* Set source */ | ||
654 | emu->i2c_capture_source = source_id; | ||
655 | } | ||
656 | return change; | ||
657 | } | ||
658 | |||
659 | static struct snd_kcontrol_new snd_audigy_i2c_capture_source = | ||
660 | { | ||
661 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
662 | .name = "Capture Source", | ||
663 | .info = snd_audigy_i2c_capture_source_info, | ||
664 | .get = snd_audigy_i2c_capture_source_get, | ||
665 | .put = snd_audigy_i2c_capture_source_put | ||
666 | }; | ||
667 | |||
668 | static int snd_audigy_i2c_volume_info(struct snd_kcontrol *kcontrol, | ||
669 | struct snd_ctl_elem_info *uinfo) | ||
670 | { | ||
671 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
672 | uinfo->count = 2; | ||
673 | uinfo->value.integer.min = 0; | ||
674 | uinfo->value.integer.max = 255; | ||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int snd_audigy_i2c_volume_get(struct snd_kcontrol *kcontrol, | ||
679 | struct snd_ctl_elem_value *ucontrol) | ||
680 | { | ||
681 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
682 | int source_id; | ||
683 | |||
684 | source_id = kcontrol->private_value; | ||
685 | |||
686 | ucontrol->value.integer.value[0] = emu->i2c_capture_volume[source_id][0]; | ||
687 | ucontrol->value.integer.value[1] = emu->i2c_capture_volume[source_id][1]; | ||
688 | return 0; | ||
689 | } | ||
690 | |||
691 | static int snd_audigy_i2c_volume_put(struct snd_kcontrol *kcontrol, | ||
692 | struct snd_ctl_elem_value *ucontrol) | ||
693 | { | ||
694 | struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol); | ||
695 | unsigned int ogain; | ||
696 | unsigned int ngain; | ||
697 | int source_id; | ||
698 | int change = 0; | ||
699 | |||
700 | source_id = kcontrol->private_value; | ||
701 | ogain = emu->i2c_capture_volume[source_id][0]; /* Left */ | ||
702 | ngain = ucontrol->value.integer.value[0]; | ||
703 | if (ngain > 0xff) | ||
704 | return 0; | ||
705 | if (ogain != ngain) { | ||
706 | if (emu->i2c_capture_source == source_id) | ||
707 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCL, ((ngain) & 0xff) ); | ||
708 | emu->i2c_capture_volume[source_id][0] = ucontrol->value.integer.value[0]; | ||
709 | change = 1; | ||
710 | } | ||
711 | ogain = emu->i2c_capture_volume[source_id][1]; /* Right */ | ||
712 | ngain = ucontrol->value.integer.value[1]; | ||
713 | if (ngain > 0xff) | ||
714 | return 0; | ||
715 | if (ogain != ngain) { | ||
716 | if (emu->i2c_capture_source == source_id) | ||
717 | snd_emu10k1_i2c_write(emu, ADC_ATTEN_ADCR, ((ngain) & 0xff)); | ||
718 | emu->i2c_capture_volume[source_id][1] = ucontrol->value.integer.value[1]; | ||
719 | change = 1; | ||
720 | } | ||
721 | |||
722 | return change; | ||
723 | } | ||
724 | |||
725 | #define I2C_VOLUME(xname,chid) \ | ||
726 | { \ | ||
727 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ | ||
728 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
729 | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \ | ||
730 | .info = snd_audigy_i2c_volume_info, \ | ||
731 | .get = snd_audigy_i2c_volume_get, \ | ||
732 | .put = snd_audigy_i2c_volume_put, \ | ||
733 | .tlv = { .p = snd_audigy_db_scale2 }, \ | ||
734 | .private_value = chid \ | ||
735 | } | ||
736 | |||
737 | |||
738 | static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] __devinitdata = { | ||
739 | I2C_VOLUME("Mic Capture Volume", 0), | ||
740 | I2C_VOLUME("Line Capture Volume", 0) | ||
741 | }; | ||
742 | |||
582 | #if 0 | 743 | #if 0 |
583 | static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) | 744 | static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) |
584 | { | 745 | { |
@@ -1179,7 +1340,9 @@ static int snd_emu10k1_shared_spdif_put(struct snd_kcontrol *kcontrol, | |||
1179 | int change = 0; | 1340 | int change = 0; |
1180 | 1341 | ||
1181 | spin_lock_irqsave(&emu->reg_lock, flags); | 1342 | spin_lock_irqsave(&emu->reg_lock, flags); |
1182 | if (emu->audigy) { | 1343 | if ( emu->card_capabilities->i2c_adc) { |
1344 | /* Do nothing for Audigy 2 ZS Notebook */ | ||
1345 | } else if (emu->audigy) { | ||
1183 | reg = inl(emu->port + A_IOCFG); | 1346 | reg = inl(emu->port + A_IOCFG); |
1184 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; | 1347 | val = ucontrol->value.integer.value[0] ? A_IOCFG_GPOUT0 : 0; |
1185 | change = (reg & A_IOCFG_GPOUT0) != val; | 1348 | change = (reg & A_IOCFG_GPOUT0) != val; |
@@ -1317,6 +1480,22 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1317 | "AMic Playback Volume", "Mic Playback Volume", | 1480 | "AMic Playback Volume", "Mic Playback Volume", |
1318 | NULL | 1481 | NULL |
1319 | }; | 1482 | }; |
1483 | static char *audigy_rename_ctls_i2c_adc[] = { | ||
1484 | //"Analog Mix Capture Volume","OLD Analog Mix Capture Volume", | ||
1485 | "Line Capture Volume", "Analog Mix Capture Volume", | ||
1486 | "Wave Playback Volume", "OLD PCM Playback Volume", | ||
1487 | "Wave Master Playback Volume", "Master Playback Volume", | ||
1488 | "AMic Playback Volume", "Old Mic Playback Volume", | ||
1489 | NULL | ||
1490 | }; | ||
1491 | static char *audigy_remove_ctls_i2c_adc[] = { | ||
1492 | /* On the Audigy2 ZS Notebook | ||
1493 | * Capture via WM8775 */ | ||
1494 | "Mic Capture Volume", | ||
1495 | "Analog Mix Capture Volume", | ||
1496 | "Aux Capture Volume", | ||
1497 | NULL | ||
1498 | }; | ||
1320 | static char *audigy_remove_ctls_1361t_adc[] = { | 1499 | static char *audigy_remove_ctls_1361t_adc[] = { |
1321 | /* On the Audigy2 the AC97 playback is piped into | 1500 | /* On the Audigy2 the AC97 playback is piped into |
1322 | * the Philips ADC for 24bit capture */ | 1501 | * the Philips ADC for 24bit capture */ |
@@ -1409,6 +1588,10 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1409 | } | 1588 | } |
1410 | for (; *c; c++) | 1589 | for (; *c; c++) |
1411 | remove_ctl(card, *c); | 1590 | remove_ctl(card, *c); |
1591 | } else if (emu->card_capabilities->i2c_adc) { | ||
1592 | c = audigy_remove_ctls_i2c_adc; | ||
1593 | for (; *c; c++) | ||
1594 | remove_ctl(card, *c); | ||
1412 | } else { | 1595 | } else { |
1413 | no_ac97: | 1596 | no_ac97: |
1414 | if (emu->card_capabilities->ecard) | 1597 | if (emu->card_capabilities->ecard) |
@@ -1422,6 +1605,8 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1422 | if (emu->audigy) | 1605 | if (emu->audigy) |
1423 | if (emu->card_capabilities->adc_1361t) | 1606 | if (emu->card_capabilities->adc_1361t) |
1424 | c = audigy_rename_ctls_1361t_adc; | 1607 | c = audigy_rename_ctls_1361t_adc; |
1608 | else if (emu->card_capabilities->i2c_adc) | ||
1609 | c = audigy_rename_ctls_i2c_adc; | ||
1425 | else | 1610 | else |
1426 | c = audigy_rename_ctls; | 1611 | c = audigy_rename_ctls; |
1427 | else | 1612 | else |
@@ -1584,6 +1769,20 @@ int __devinit snd_emu10k1_mixer(struct snd_emu10k1 *emu, | |||
1584 | if (err < 0) | 1769 | if (err < 0) |
1585 | return err; | 1770 | return err; |
1586 | } | 1771 | } |
1772 | |||
1773 | if ( emu->card_capabilities->i2c_adc) { | ||
1774 | int i; | ||
1775 | |||
1776 | err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_capture_source, emu)); | ||
1777 | if (err < 0) | ||
1778 | return err; | ||
1779 | |||
1780 | for (i = 0; i < ARRAY_SIZE(snd_audigy_i2c_volume_ctls); i++) { | ||
1781 | err = snd_ctl_add(card, snd_ctl_new1(&snd_audigy_i2c_volume_ctls[i], emu)); | ||
1782 | if (err < 0) | ||
1783 | return err; | ||
1784 | } | ||
1785 | } | ||
1587 | 1786 | ||
1588 | return 0; | 1787 | return 0; |
1589 | } | 1788 | } |
diff --git a/sound/pci/emu10k1/io.c b/sound/pci/emu10k1/io.c index 27ab7d1788a0..116e1c8d9361 100644 --- a/sound/pci/emu10k1/io.c +++ b/sound/pci/emu10k1/io.c | |||
@@ -30,6 +30,7 @@ | |||
30 | #include <sound/core.h> | 30 | #include <sound/core.h> |
31 | #include <sound/emu10k1.h> | 31 | #include <sound/emu10k1.h> |
32 | #include <linux/delay.h> | 32 | #include <linux/delay.h> |
33 | #include "p17v.h" | ||
33 | 34 | ||
34 | unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) | 35 | unsigned int snd_emu10k1_ptr_read(struct snd_emu10k1 * emu, unsigned int reg, unsigned int chn) |
35 | { | 36 | { |
@@ -167,6 +168,64 @@ int snd_emu10k1_spi_write(struct snd_emu10k1 * emu, | |||
167 | return 0; | 168 | return 0; |
168 | } | 169 | } |
169 | 170 | ||
171 | /* The ADC does not support i2c read, so only write is implemented */ | ||
172 | int snd_emu10k1_i2c_write(struct snd_emu10k1 *emu, | ||
173 | u32 reg, | ||
174 | u32 value) | ||
175 | { | ||
176 | u32 tmp; | ||
177 | int timeout = 0; | ||
178 | int status; | ||
179 | int retry; | ||
180 | if ((reg > 0x7f) || (value > 0x1ff)) { | ||
181 | snd_printk(KERN_ERR "i2c_write: invalid values.\n"); | ||
182 | return -EINVAL; | ||
183 | } | ||
184 | |||
185 | tmp = reg << 25 | value << 16; | ||
186 | // snd_printk("I2C-write:reg=0x%x, value=0x%x\n", reg, value); | ||
187 | /* Not sure what this I2C channel controls. */ | ||
188 | /* snd_emu10k1_ptr_write(emu, P17V_I2C_0, 0, tmp); */ | ||
189 | |||
190 | /* This controls the I2C connected to the WM8775 ADC Codec */ | ||
191 | snd_emu10k1_ptr20_write(emu, P17V_I2C_1, 0, tmp); | ||
192 | tmp = snd_emu10k1_ptr20_read(emu, P17V_I2C_1, 0); /* write post */ | ||
193 | |||
194 | for (retry = 0; retry < 10; retry++) { | ||
195 | /* Send the data to i2c */ | ||
196 | //tmp = snd_emu10k1_ptr_read(emu, P17V_I2C_ADDR, 0); | ||
197 | //tmp = tmp & ~(I2C_A_ADC_READ|I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD_MASK); | ||
198 | tmp = 0; | ||
199 | tmp = tmp | (I2C_A_ADC_LAST|I2C_A_ADC_START|I2C_A_ADC_ADD); | ||
200 | snd_emu10k1_ptr20_write(emu, P17V_I2C_ADDR, 0, tmp); | ||
201 | |||
202 | /* Wait till the transaction ends */ | ||
203 | while (1) { | ||
204 | udelay(10); | ||
205 | status = snd_emu10k1_ptr20_read(emu, P17V_I2C_ADDR, 0); | ||
206 | // snd_printk("I2C:status=0x%x\n", status); | ||
207 | timeout++; | ||
208 | if ((status & I2C_A_ADC_START) == 0) | ||
209 | break; | ||
210 | |||
211 | if (timeout > 1000) { | ||
212 | snd_printk("emu10k1:I2C:timeout status=0x%x\n", status); | ||
213 | break; | ||
214 | } | ||
215 | } | ||
216 | //Read back and see if the transaction is successful | ||
217 | if ((status & I2C_A_ADC_ABORT) == 0) | ||
218 | break; | ||
219 | } | ||
220 | |||
221 | if (retry == 10) { | ||
222 | snd_printk(KERN_ERR "Writing to ADC failed!\n"); | ||
223 | return -EINVAL; | ||
224 | } | ||
225 | |||
226 | return 0; | ||
227 | } | ||
228 | |||
170 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) | 229 | int snd_emu1010_fpga_write(struct snd_emu10k1 * emu, int reg, int value) |
171 | { | 230 | { |
172 | if (reg < 0 || reg > 0x3f) | 231 | if (reg < 0 || reg > 0x3f) |
diff --git a/sound/pci/emu10k1/p17v.h b/sound/pci/emu10k1/p17v.h index 7ddb5be632cf..4ef5f68a9cd0 100644 --- a/sound/pci/emu10k1/p17v.h +++ b/sound/pci/emu10k1/p17v.h | |||
@@ -43,6 +43,53 @@ | |||
43 | #define P17V_I2C_ADDR 0x3d /* I2C Address */ | 43 | #define P17V_I2C_ADDR 0x3d /* I2C Address */ |
44 | #define P17V_I2C_0 0x3e /* I2C Data */ | 44 | #define P17V_I2C_0 0x3e /* I2C Data */ |
45 | #define P17V_I2C_1 0x3f /* I2C Data */ | 45 | #define P17V_I2C_1 0x3f /* I2C Data */ |
46 | /* I2C values */ | ||
47 | #define I2C_A_ADC_ADD_MASK 0x000000fe /*The address is a 7 bit address */ | ||
48 | #define I2C_A_ADC_RW_MASK 0x00000001 /*bit mask for R/W */ | ||
49 | #define I2C_A_ADC_TRANS_MASK 0x00000010 /*Bit mask for I2c address DAC value */ | ||
50 | #define I2C_A_ADC_ABORT_MASK 0x00000020 /*Bit mask for I2C transaction abort flag */ | ||
51 | #define I2C_A_ADC_LAST_MASK 0x00000040 /*Bit mask for Last word transaction */ | ||
52 | #define I2C_A_ADC_BYTE_MASK 0x00000080 /*Bit mask for Byte Mode */ | ||
53 | |||
54 | #define I2C_A_ADC_ADD 0x00000034 /*This is the Device address for ADC */ | ||
55 | #define I2C_A_ADC_READ 0x00000001 /*To perform a read operation */ | ||
56 | #define I2C_A_ADC_START 0x00000100 /*Start I2C transaction */ | ||
57 | #define I2C_A_ADC_ABORT 0x00000200 /*I2C transaction abort */ | ||
58 | #define I2C_A_ADC_LAST 0x00000400 /*I2C last transaction */ | ||
59 | #define I2C_A_ADC_BYTE 0x00000800 /*I2C one byte mode */ | ||
60 | |||
61 | #define I2C_D_ADC_REG_MASK 0xfe000000 /*ADC address register */ | ||
62 | #define I2C_D_ADC_DAT_MASK 0x01ff0000 /*ADC data register */ | ||
63 | |||
64 | #define ADC_TIMEOUT 0x00000007 /*ADC Timeout Clock Disable */ | ||
65 | #define ADC_IFC_CTRL 0x0000000b /*ADC Interface Control */ | ||
66 | #define ADC_MASTER 0x0000000c /*ADC Master Mode Control */ | ||
67 | #define ADC_POWER 0x0000000d /*ADC PowerDown Control */ | ||
68 | #define ADC_ATTEN_ADCL 0x0000000e /*ADC Attenuation ADCL */ | ||
69 | #define ADC_ATTEN_ADCR 0x0000000f /*ADC Attenuation ADCR */ | ||
70 | #define ADC_ALC_CTRL1 0x00000010 /*ADC ALC Control 1 */ | ||
71 | #define ADC_ALC_CTRL2 0x00000011 /*ADC ALC Control 2 */ | ||
72 | #define ADC_ALC_CTRL3 0x00000012 /*ADC ALC Control 3 */ | ||
73 | #define ADC_NOISE_CTRL 0x00000013 /*ADC Noise Gate Control */ | ||
74 | #define ADC_LIMIT_CTRL 0x00000014 /*ADC Limiter Control */ | ||
75 | #define ADC_MUX 0x00000015 /*ADC Mux offset */ | ||
76 | #if 0 | ||
77 | /* FIXME: Not tested yet. */ | ||
78 | #define ADC_GAIN_MASK 0x000000ff //Mask for ADC Gain | ||
79 | #define ADC_ZERODB 0x000000cf //Value to set ADC to 0dB | ||
80 | #define ADC_MUTE_MASK 0x000000c0 //Mask for ADC mute | ||
81 | #define ADC_MUTE 0x000000c0 //Value to mute ADC | ||
82 | #define ADC_OSR 0x00000008 //Mask for ADC oversample rate select | ||
83 | #define ADC_TIMEOUT_DISABLE 0x00000008 //Value and mask to disable Timeout clock | ||
84 | #define ADC_HPF_DISABLE 0x00000100 //Value and mask to disable High pass filter | ||
85 | #define ADC_TRANWIN_MASK 0x00000070 //Mask for Length of Transient Window | ||
86 | #endif | ||
87 | |||
88 | #define ADC_MUX_MASK 0x0000000f //Mask for ADC Mux | ||
89 | #define ADC_MUX_0 0x00000001 //Value to select Unknown at ADC Mux (Not used) | ||
90 | #define ADC_MUX_1 0x00000002 //Value to select Unknown at ADC Mux (Not used) | ||
91 | #define ADC_MUX_2 0x00000004 //Value to select Mic at ADC Mux | ||
92 | #define ADC_MUX_3 0x00000008 //Value to select Line-In at ADC Mux | ||
46 | 93 | ||
47 | #define P17V_START_AUDIO 0x40 /* Start Audio bit */ | 94 | #define P17V_START_AUDIO 0x40 /* Start Audio bit */ |
48 | /* 41 - 47: Reserved */ | 95 | /* 41 - 47: Reserved */ |