aboutsummaryrefslogtreecommitdiffstats
path: root/sound/pci/emu10k1/emumixer.c
diff options
context:
space:
mode:
authorJames Courtier-Dutton <James@superbug.co.uk>2006-12-06 10:58:02 -0500
committerJaroslav Kysela <perex@suse.cz>2007-02-09 03:02:17 -0500
commit184c1e2c4c4221c2b8d1e16c33314595373fa73f (patch)
treef041f147ba8c92e5587163d0b76863fdf4f0318b /sound/pci/emu10k1/emumixer.c
parent9ed1261e3e617d99b0eb74041d0337ff664e4f5b (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/pci/emu10k1/emumixer.c')
-rw-r--r--sound/pci/emu10k1/emumixer.c201
1 files changed, 200 insertions, 1 deletions
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
45static DECLARE_TLV_DB_SCALE(snd_audigy_db_scale2, -10350, 50, 1); /* WM8775 gain scale */
46
42static int snd_emu10k1_spdif_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 47static 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
587static 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
608static 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
617static 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
659static 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
668static 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
678static 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
691static 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
738static 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
583static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 744static 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}