diff options
author | Pavel Hofman <dustin@seznam.cz> | 2007-12-03 06:44:28 -0500 |
---|---|---|
committer | Jaroslav Kysela <perex@perex.cz> | 2008-01-31 11:29:30 -0500 |
commit | 6632d64b0b596b9588b607806ac6d36c8c2c9696 (patch) | |
tree | 0e8126af6c2c47e2b981c7ab7d8cf29aaaee8360 /sound/pci/ice1712/prodigy192.c | |
parent | acec30ffffe1eee07e3202cff03e7ca8350d250f (diff) |
[ALSA] switching rate in STAC9460 codec of Prodigy192
* support for switching rate in STAC9460 - using set_rate_val of the akm
infrastructure
* listing all STAC9460 registers in proc
* disabling mpu401 device for Prodigy192 - otherwise the currently
flawed mpu401 code hangs kernel when opening the midi device
* removing old unused commented-out code
Signed-off-by: Pavel Hofman <dustin@seznam.cz>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Signed-off-by: Jaroslav Kysela <perex@perex.cz>
Diffstat (limited to 'sound/pci/ice1712/prodigy192.c')
-rw-r--r-- | sound/pci/ice1712/prodigy192.c | 271 |
1 files changed, 116 insertions, 155 deletions
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c index 4b21d5c1c4ff..6d81a1c61d41 100644 --- a/sound/pci/ice1712/prodigy192.c +++ b/sound/pci/ice1712/prodigy192.c | |||
@@ -81,6 +81,24 @@ static inline unsigned char stac9460_get(struct snd_ice1712 *ice, int reg) | |||
81 | /* | 81 | /* |
82 | * DAC mute control | 82 | * DAC mute control |
83 | */ | 83 | */ |
84 | |||
85 | /* | ||
86 | * idx = STAC9460 volume register number, mute: 0 = mute, 1 = unmute | ||
87 | */ | ||
88 | static int stac9460_dac_mute(struct snd_ice1712 *ice, int idx, | ||
89 | unsigned char mute) | ||
90 | { | ||
91 | unsigned char new, old; | ||
92 | int change; | ||
93 | old = stac9460_get(ice, idx); | ||
94 | new = (~mute << 7 & 0x80) | (old & ~0x80); | ||
95 | change = (new != old); | ||
96 | if (change) | ||
97 | /*printk ("Volume register 0x%02x: 0x%02x\n", idx, new);*/ | ||
98 | stac9460_put(ice, idx, new); | ||
99 | return change; | ||
100 | } | ||
101 | |||
84 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info | 102 | #define stac9460_dac_mute_info snd_ctl_boolean_mono_info |
85 | 103 | ||
86 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 104 | static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
@@ -101,20 +119,18 @@ static int stac9460_dac_mute_get(struct snd_kcontrol *kcontrol, struct snd_ctl_e | |||
101 | static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | 119 | static int stac9460_dac_mute_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) |
102 | { | 120 | { |
103 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | 121 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); |
104 | unsigned char new, old; | 122 | int idx, change; |
105 | int idx; | ||
106 | int change; | ||
107 | 123 | ||
108 | if (kcontrol->private_value) | 124 | if (kcontrol->private_value) |
109 | idx = STAC946X_MASTER_VOLUME; | 125 | idx = STAC946X_MASTER_VOLUME; |
110 | else | 126 | else |
111 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; | 127 | idx = snd_ctl_get_ioffidx(kcontrol, &ucontrol->id) + STAC946X_LF_VOLUME; |
112 | old = stac9460_get(ice, idx); | 128 | /* due to possible conflicts with stac9460_set_rate_val, mutexing */ |
113 | new = (~ucontrol->value.integer.value[0]<< 7 & 0x80) | (old & ~0x80); | 129 | mutex_lock(&ice->spec.prodigy192.mute_mutex); |
114 | change = (new != old); | 130 | /*printk("Mute put: reg 0x%02x, ctrl value: 0x%02x\n", idx, |
115 | if (change) | 131 | ucontrol->value.integer.value[0]);*/ |
116 | stac9460_put(ice, idx, new); | 132 | change = stac9460_dac_mute(ice, idx, ucontrol->value.integer.value[0]); |
117 | 133 | mutex_unlock(&ice->spec.prodigy192.mute_mutex); | |
118 | return change; | 134 | return change; |
119 | } | 135 | } |
120 | 136 | ||
@@ -162,6 +178,8 @@ static int stac9460_dac_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
162 | ovol = 0x7f - (tmp & 0x7f); | 178 | ovol = 0x7f - (tmp & 0x7f); |
163 | change = (ovol != nvol); | 179 | change = (ovol != nvol); |
164 | if (change) { | 180 | if (change) { |
181 | ovol = (0x7f - nvol) | (tmp & 0x80); | ||
182 | /*printk("DAC Volume: reg 0x%02x: 0x%02x\n", idx, ovol);*/ | ||
165 | stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); | 183 | stac9460_put(ice, idx, (0x7f - nvol) | (tmp & 0x80)); |
166 | } | 184 | } |
167 | return change; | 185 | return change; |
@@ -251,121 +269,6 @@ static int stac9460_adc_vol_put(struct snd_kcontrol *kcontrol, struct snd_ctl_el | |||
251 | return change; | 269 | return change; |
252 | } | 270 | } |
253 | 271 | ||
254 | #if 0 | ||
255 | /* | ||
256 | * Headphone Amplifier | ||
257 | */ | ||
258 | static int aureon_set_headphone_amp(struct snd_ice1712 *ice, int enable) | ||
259 | { | ||
260 | unsigned int tmp, tmp2; | ||
261 | |||
262 | tmp2 = tmp = snd_ice1712_gpio_read(ice); | ||
263 | if (enable) | ||
264 | tmp |= AUREON_HP_SEL; | ||
265 | else | ||
266 | tmp &= ~ AUREON_HP_SEL; | ||
267 | if (tmp != tmp2) { | ||
268 | snd_ice1712_gpio_write(ice, tmp); | ||
269 | return 1; | ||
270 | } | ||
271 | return 0; | ||
272 | } | ||
273 | |||
274 | static int aureon_get_headphone_amp(struct snd_ice1712 *ice) | ||
275 | { | ||
276 | unsigned int tmp = snd_ice1712_gpio_read(ice); | ||
277 | |||
278 | return ( tmp & AUREON_HP_SEL )!= 0; | ||
279 | } | ||
280 | |||
281 | #define aureon_bool_info snd_ctl_boolean_mono_info | ||
282 | |||
283 | static int aureon_hpamp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
284 | { | ||
285 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
286 | |||
287 | ucontrol->value.integer.value[0] = aureon_get_headphone_amp(ice); | ||
288 | return 0; | ||
289 | } | ||
290 | |||
291 | |||
292 | static int aureon_hpamp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
293 | { | ||
294 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
295 | |||
296 | return aureon_set_headphone_amp(ice,ucontrol->value.integer.value[0]); | ||
297 | } | ||
298 | |||
299 | /* | ||
300 | * Deemphasis | ||
301 | */ | ||
302 | static int aureon_deemp_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
303 | { | ||
304 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
305 | ucontrol->value.integer.value[0] = (wm_get(ice, WM_DAC_CTRL2) & 0xf) == 0xf; | ||
306 | return 0; | ||
307 | } | ||
308 | |||
309 | static int aureon_deemp_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
310 | { | ||
311 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
312 | int temp, temp2; | ||
313 | temp2 = temp = wm_get(ice, WM_DAC_CTRL2); | ||
314 | if (ucontrol->value.integer.value[0]) | ||
315 | temp |= 0xf; | ||
316 | else | ||
317 | temp &= ~0xf; | ||
318 | if (temp != temp2) { | ||
319 | wm_put(ice, WM_DAC_CTRL2, temp); | ||
320 | return 1; | ||
321 | } | ||
322 | return 0; | ||
323 | } | ||
324 | |||
325 | /* | ||
326 | * ADC Oversampling | ||
327 | */ | ||
328 | static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_info *uinfo) | ||
329 | { | ||
330 | static char *texts[2] = { "128x", "64x" }; | ||
331 | |||
332 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
333 | uinfo->count = 1; | ||
334 | uinfo->value.enumerated.items = 2; | ||
335 | |||
336 | if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) | ||
337 | uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1; | ||
338 | strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]); | ||
339 | |||
340 | return 0; | ||
341 | } | ||
342 | |||
343 | static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
344 | { | ||
345 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
346 | ucontrol->value.enumerated.item[0] = (wm_get(ice, WM_MASTER) & 0x8) == 0x8; | ||
347 | return 0; | ||
348 | } | ||
349 | |||
350 | static int aureon_oversampling_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol) | ||
351 | { | ||
352 | int temp, temp2; | ||
353 | struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol); | ||
354 | |||
355 | temp2 = temp = wm_get(ice, WM_MASTER); | ||
356 | |||
357 | if (ucontrol->value.enumerated.item[0]) | ||
358 | temp |= 0x8; | ||
359 | else | ||
360 | temp &= ~0x8; | ||
361 | |||
362 | if (temp != temp2) { | ||
363 | wm_put(ice, WM_MASTER, temp); | ||
364 | return 1; | ||
365 | } | ||
366 | return 0; | ||
367 | } | ||
368 | #endif | ||
369 | static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, | 272 | static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol, |
370 | struct snd_ctl_elem_info *uinfo) | 273 | struct snd_ctl_elem_info *uinfo) |
371 | { | 274 | { |
@@ -407,6 +310,56 @@ static int stac9460_mic_sw_put(struct snd_kcontrol *kcontrol, | |||
407 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); | 310 | stac9460_put(ice, STAC946X_GENERAL_PURPOSE, new); |
408 | return change; | 311 | return change; |
409 | } | 312 | } |
313 | /* | ||
314 | * Handler for setting correct codec rate - called when rate change is detected | ||
315 | */ | ||
316 | static void stac9460_set_rate_val(struct snd_akm4xxx *ak, unsigned int rate) | ||
317 | { | ||
318 | unsigned char old, new; | ||
319 | int idx; | ||
320 | unsigned char changed[7]; | ||
321 | struct snd_ice1712 *ice = ak->private_data[0]; | ||
322 | |||
323 | if (rate == 0) /* no hint - S/PDIF input is master, simply return */ | ||
324 | return; | ||
325 | else if (rate <= 48000) | ||
326 | new = 0x08; /* 256x, base rate mode */ | ||
327 | else if (rate <= 96000) | ||
328 | new = 0x11; /* 256x, mid rate mode */ | ||
329 | else | ||
330 | new = 0x12; /* 128x, high rate mode */ | ||
331 | old = stac9460_get(ice, STAC946X_MASTER_CLOCKING); | ||
332 | if (old == new) | ||
333 | return; | ||
334 | /* change detected, setting master clock, muting first */ | ||
335 | /* due to possible conflicts with mute controls - mutexing */ | ||
336 | mutex_lock(&ice->spec.prodigy192.mute_mutex); | ||
337 | /* we have to remember current mute status for each DAC */ | ||
338 | for (idx = 0; idx < 7 ; ++idx) | ||
339 | changed[idx] = stac9460_dac_mute(ice, | ||
340 | STAC946X_MASTER_VOLUME + idx, 0); | ||
341 | /*printk("Rate change: %d, new MC: 0x%02x\n", rate, new);*/ | ||
342 | stac9460_put(ice, STAC946X_MASTER_CLOCKING, new); | ||
343 | udelay(10); | ||
344 | /* unmuting - only originally unmuted dacs - | ||
345 | * i.e. those changed when muting */ | ||
346 | for (idx = 0; idx < 7 ; ++idx) { | ||
347 | if (changed[idx]) | ||
348 | stac9460_dac_mute(ice, STAC946X_MASTER_VOLUME + idx, 1); | ||
349 | } | ||
350 | mutex_unlock(&ice->spec.prodigy192.mute_mutex); | ||
351 | } | ||
352 | |||
353 | /* using akm infrastructure for setting rate of the codec */ | ||
354 | static struct snd_akm4xxx akmlike_stac9460 __devinitdata = { | ||
355 | .type = NON_AKM, /* special value */ | ||
356 | .num_adcs = 6, /* not used in any way, just for completeness */ | ||
357 | .num_dacs = 2, | ||
358 | .ops = { | ||
359 | .set_rate_val = stac9460_set_rate_val | ||
360 | } | ||
361 | }; | ||
362 | |||
410 | 363 | ||
411 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); | 364 | static const DECLARE_TLV_DB_SCALE(db_scale_dac, -19125, 75, 0); |
412 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); | 365 | static const DECLARE_TLV_DB_SCALE(db_scale_adc, 0, 150, 0); |
@@ -483,39 +436,8 @@ static struct snd_kcontrol_new stac_controls[] __devinitdata = { | |||
483 | .put = stac9460_mic_sw_put, | 436 | .put = stac9460_mic_sw_put, |
484 | 437 | ||
485 | }, | 438 | }, |
486 | #if 0 | ||
487 | { | ||
488 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
489 | .name = "Capture Route", | ||
490 | .info = wm_adc_mux_info, | ||
491 | .get = wm_adc_mux_get, | ||
492 | .put = wm_adc_mux_put, | ||
493 | }, | ||
494 | { | ||
495 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
496 | .name = "Headphone Amplifier Switch", | ||
497 | .info = aureon_bool_info, | ||
498 | .get = aureon_hpamp_get, | ||
499 | .put = aureon_hpamp_put | ||
500 | }, | ||
501 | { | ||
502 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
503 | .name = "DAC Deemphasis Switch", | ||
504 | .info = aureon_bool_info, | ||
505 | .get = aureon_deemp_get, | ||
506 | .put = aureon_deemp_put | ||
507 | }, | ||
508 | { | ||
509 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | ||
510 | .name = "ADC Oversampling", | ||
511 | .info = aureon_oversampling_info, | ||
512 | .get = aureon_oversampling_get, | ||
513 | .put = aureon_oversampling_put | ||
514 | }, | ||
515 | #endif | ||
516 | }; | 439 | }; |
517 | 440 | ||
518 | |||
519 | /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ | 441 | /* AK4114 - ICE1724 connections on Prodigy192 + MI/ODI/O */ |
520 | /* CDTO (pin 32) -- GPIO11 pin 86 | 442 | /* CDTO (pin 32) -- GPIO11 pin 86 |
521 | * CDTI (pin 33) -- GPIO10 pin 77 | 443 | * CDTI (pin 33) -- GPIO10 pin 77 |
@@ -720,6 +642,27 @@ static int prodigy192_ak4114_init(struct snd_ice1712 *ice) | |||
720 | ice, &ice->spec.prodigy192.ak4114); | 642 | ice, &ice->spec.prodigy192.ak4114); |
721 | } | 643 | } |
722 | 644 | ||
645 | static void stac9460_proc_regs_read(struct snd_info_entry *entry, | ||
646 | struct snd_info_buffer *buffer) | ||
647 | { | ||
648 | struct snd_ice1712 *ice = (struct snd_ice1712 *)entry->private_data; | ||
649 | int reg, val; | ||
650 | /* registers 0x0 - 0x14 */ | ||
651 | for (reg = 0; reg <= 0x15; reg++) { | ||
652 | val = stac9460_get(ice, reg); | ||
653 | snd_iprintf(buffer, "0x%02x = 0x%02x\n", reg, val); | ||
654 | } | ||
655 | } | ||
656 | |||
657 | |||
658 | static void stac9460_proc_init(struct snd_ice1712 *ice) | ||
659 | { | ||
660 | struct snd_info_entry *entry; | ||
661 | if (!snd_card_proc_new(ice->card, "stac9460_codec", &entry)) | ||
662 | snd_info_set_text_ops(entry, ice, stac9460_proc_regs_read); | ||
663 | } | ||
664 | |||
665 | |||
723 | static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | 666 | static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) |
724 | { | 667 | { |
725 | unsigned int i; | 668 | unsigned int i; |
@@ -746,6 +689,7 @@ static int __devinit prodigy192_add_controls(struct snd_ice1712 *ice) | |||
746 | if (err < 0) | 689 | if (err < 0) |
747 | return err; | 690 | return err; |
748 | } | 691 | } |
692 | stac9460_proc_init(ice); | ||
749 | return 0; | 693 | return 0; |
750 | } | 694 | } |
751 | 695 | ||
@@ -778,6 +722,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
778 | { | 722 | { |
779 | static const unsigned short stac_inits_prodigy[] = { | 723 | static const unsigned short stac_inits_prodigy[] = { |
780 | STAC946X_RESET, 0, | 724 | STAC946X_RESET, 0, |
725 | STAC946X_MASTER_CLOCKING, 0x11, | ||
781 | /* STAC946X_MASTER_VOLUME, 0, | 726 | /* STAC946X_MASTER_VOLUME, 0, |
782 | STAC946X_LF_VOLUME, 0, | 727 | STAC946X_LF_VOLUME, 0, |
783 | STAC946X_RF_VOLUME, 0, | 728 | STAC946X_RF_VOLUME, 0, |
@@ -789,6 +734,7 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
789 | }; | 734 | }; |
790 | const unsigned short *p; | 735 | const unsigned short *p; |
791 | int err = 0; | 736 | int err = 0; |
737 | struct snd_akm4xxx *ak; | ||
792 | 738 | ||
793 | /* prodigy 192 */ | 739 | /* prodigy 192 */ |
794 | ice->num_total_dacs = 6; | 740 | ice->num_total_dacs = 6; |
@@ -799,6 +745,15 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
799 | p = stac_inits_prodigy; | 745 | p = stac_inits_prodigy; |
800 | for (; *p != (unsigned short)-1; p += 2) | 746 | for (; *p != (unsigned short)-1; p += 2) |
801 | stac9460_put(ice, p[0], p[1]); | 747 | stac9460_put(ice, p[0], p[1]); |
748 | /* reusing the akm codecs infrastructure, | ||
749 | * for setting rate on stac9460 */ | ||
750 | ak = ice->akm = kmalloc(sizeof(struct snd_akm4xxx), GFP_KERNEL); | ||
751 | if (!ak) | ||
752 | return -ENOMEM; | ||
753 | ice->akm_codecs = 1; | ||
754 | err = snd_ice1712_akm4xxx_init(ak, &akmlike_stac9460, NULL, ice); | ||
755 | if (err < 0) | ||
756 | return err; | ||
802 | 757 | ||
803 | /* MI/ODI/O add on card with AK4114 */ | 758 | /* MI/ODI/O add on card with AK4114 */ |
804 | if (prodigy192_miodio_exists(ice)) { | 759 | if (prodigy192_miodio_exists(ice)) { |
@@ -812,6 +767,8 @@ static int __devinit prodigy192_init(struct snd_ice1712 *ice) | |||
812 | if (err < 0) | 767 | if (err < 0) |
813 | return err; | 768 | return err; |
814 | 769 | ||
770 | mutex_init(&ice->spec.prodigy192.mute_mutex); | ||
771 | |||
815 | return 0; | 772 | return 0; |
816 | } | 773 | } |
817 | 774 | ||
@@ -854,6 +811,10 @@ struct snd_ice1712_card_info snd_vt1724_prodigy192_cards[] __devinitdata = { | |||
854 | .build_controls = prodigy192_add_controls, | 811 | .build_controls = prodigy192_add_controls, |
855 | .eeprom_size = sizeof(prodigy71_eeprom), | 812 | .eeprom_size = sizeof(prodigy71_eeprom), |
856 | .eeprom_data = prodigy71_eeprom, | 813 | .eeprom_data = prodigy71_eeprom, |
814 | /* the current MPU401 code loops infinitely | ||
815 | * when opening midi device | ||
816 | */ | ||
817 | .no_mpu401 = 1, | ||
857 | }, | 818 | }, |
858 | { } /* terminator */ | 819 | { } /* terminator */ |
859 | }; | 820 | }; |