aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOndrej Zary <linux@rainbow-software.org>2014-11-03 15:35:48 -0500
committerTakashi Iwai <tiwai@suse.de>2014-11-04 04:31:30 -0500
commit2603fe21b764eb7412598c8c6cd6199fb8b1d9c5 (patch)
tree689fac231a867bd8e14da85e0194b2c1c0524ac2
parent31604d35db18c1382c7ee9fa836ff9ab0b4d2751 (diff)
ALSA: es18xx: Add GPO controls
Add GPO0 and GPO1 (General Purpose Outputs) controls to mixer. These can be used on some cards to control amplifier mute (seen in ES1868 datasheet) or additional onboard chips such as QX2130 QXpander processor. These GPOs are present on ES1868, ES1869, ES1887 and ES1888 chips. Tested on ES1868 with QX2130. Signed-off-by: Ondrej Zary <linux@rainbow-software.org> Signed-off-by: Takashi Iwai <tiwai@suse.de>
-rw-r--r--sound/isa/es18xx.c52
1 files changed, 42 insertions, 10 deletions
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 63e7323e218f..b481bb8c31bc 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -156,6 +156,7 @@ struct snd_es18xx {
156#define ES18XX_I2S 0x0200 /* I2S mixer control */ 156#define ES18XX_I2S 0x0200 /* I2S mixer control */
157#define ES18XX_MUTEREC 0x0400 /* Record source can be muted */ 157#define ES18XX_MUTEREC 0x0400 /* Record source can be muted */
158#define ES18XX_CONTROL 0x0800 /* Has control ports */ 158#define ES18XX_CONTROL 0x0800 /* Has control ports */
159#define ES18XX_GPO_2BIT 0x1000 /* GPO0,1 controlled by PM port */
159 160
160/* Power Management */ 161/* Power Management */
161#define ES18XX_PM 0x07 162#define ES18XX_PM 0x07
@@ -1120,11 +1121,14 @@ static int snd_es18xx_reg_read(struct snd_es18xx *chip, unsigned char reg)
1120 return snd_es18xx_read(chip, reg); 1121 return snd_es18xx_read(chip, reg);
1121} 1122}
1122 1123
1123#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, invert) \ 1124#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, flags) \
1124{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \ 1125{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
1125 .info = snd_es18xx_info_single, \ 1126 .info = snd_es18xx_info_single, \
1126 .get = snd_es18xx_get_single, .put = snd_es18xx_put_single, \ 1127 .get = snd_es18xx_get_single, .put = snd_es18xx_put_single, \
1127 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) } 1128 .private_value = reg | (shift << 8) | (mask << 16) | (flags << 24) }
1129
1130#define ES18XX_FL_INVERT (1 << 0)
1131#define ES18XX_FL_PMPORT (1 << 1)
1128 1132
1129static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo) 1133static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1130{ 1134{
@@ -1143,10 +1147,14 @@ static int snd_es18xx_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
1143 int reg = kcontrol->private_value & 0xff; 1147 int reg = kcontrol->private_value & 0xff;
1144 int shift = (kcontrol->private_value >> 8) & 0xff; 1148 int shift = (kcontrol->private_value >> 8) & 0xff;
1145 int mask = (kcontrol->private_value >> 16) & 0xff; 1149 int mask = (kcontrol->private_value >> 16) & 0xff;
1146 int invert = (kcontrol->private_value >> 24) & 0xff; 1150 int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
1151 int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
1147 int val; 1152 int val;
1148 1153
1149 val = snd_es18xx_reg_read(chip, reg); 1154 if (pm_port)
1155 val = inb(chip->port + ES18XX_PM);
1156 else
1157 val = snd_es18xx_reg_read(chip, reg);
1150 ucontrol->value.integer.value[0] = (val >> shift) & mask; 1158 ucontrol->value.integer.value[0] = (val >> shift) & mask;
1151 if (invert) 1159 if (invert)
1152 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0]; 1160 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
@@ -1159,7 +1167,8 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
1159 int reg = kcontrol->private_value & 0xff; 1167 int reg = kcontrol->private_value & 0xff;
1160 int shift = (kcontrol->private_value >> 8) & 0xff; 1168 int shift = (kcontrol->private_value >> 8) & 0xff;
1161 int mask = (kcontrol->private_value >> 16) & 0xff; 1169 int mask = (kcontrol->private_value >> 16) & 0xff;
1162 int invert = (kcontrol->private_value >> 24) & 0xff; 1170 int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
1171 int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
1163 unsigned char val; 1172 unsigned char val;
1164 1173
1165 val = (ucontrol->value.integer.value[0] & mask); 1174 val = (ucontrol->value.integer.value[0] & mask);
@@ -1167,6 +1176,15 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
1167 val = mask - val; 1176 val = mask - val;
1168 mask <<= shift; 1177 mask <<= shift;
1169 val <<= shift; 1178 val <<= shift;
1179 if (pm_port) {
1180 unsigned char cur = inb(chip->port + ES18XX_PM);
1181
1182 if ((cur & mask) == val)
1183 return 0;
1184 outb((cur & ~mask) | val, chip->port + ES18XX_PM);
1185 return 1;
1186 }
1187
1170 return snd_es18xx_reg_bits(chip, reg, mask, val) != val; 1188 return snd_es18xx_reg_bits(chip, reg, mask, val) != val;
1171} 1189}
1172 1190
@@ -1288,7 +1306,7 @@ static struct snd_kcontrol_new snd_es18xx_opt_speaker =
1288 ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0); 1306 ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
1289 1307
1290static struct snd_kcontrol_new snd_es18xx_opt_1869[] = { 1308static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
1291ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1), 1309ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, ES18XX_FL_INVERT),
1292ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0), 1310ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
1293ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0), 1311ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
1294ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0) 1312ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
@@ -1347,6 +1365,11 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = {
1347ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0), 1365ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
1348}; 1366};
1349 1367
1368static struct snd_kcontrol_new snd_es18xx_opt_gpo_2bit[] = {
1369ES18XX_SINGLE("GPO0 Switch", 0, ES18XX_PM, 0, 1, ES18XX_FL_PMPORT),
1370ES18XX_SINGLE("GPO1 Switch", 0, ES18XX_PM, 1, 1, ES18XX_FL_PMPORT),
1371};
1372
1350static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg) 1373static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
1351{ 1374{
1352 int data; 1375 int data;
@@ -1613,10 +1636,10 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
1613 1636
1614 switch (chip->version) { 1637 switch (chip->version) {
1615 case 0x1868: 1638 case 0x1868:
1616 chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL; 1639 chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_GPO_2BIT;
1617 break; 1640 break;
1618 case 0x1869: 1641 case 0x1869:
1619 chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV; 1642 chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV | ES18XX_GPO_2BIT;
1620 break; 1643 break;
1621 case 0x1878: 1644 case 0x1878:
1622 chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL; 1645 chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
@@ -1626,7 +1649,7 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
1626 break; 1649 break;
1627 case 0x1887: 1650 case 0x1887:
1628 case 0x1888: 1651 case 0x1888:
1629 chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME; 1652 chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_GPO_2BIT;
1630 break; 1653 break;
1631 default: 1654 default:
1632 snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n", 1655 snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
@@ -1928,6 +1951,15 @@ static int snd_es18xx_mixer(struct snd_card *card)
1928 return err; 1951 return err;
1929 } 1952 }
1930 } 1953 }
1954 if (chip->caps & ES18XX_GPO_2BIT) {
1955 for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_gpo_2bit); idx++) {
1956 err = snd_ctl_add(card,
1957 snd_ctl_new1(&snd_es18xx_opt_gpo_2bit[idx],
1958 chip));
1959 if (err < 0)
1960 return err;
1961 }
1962 }
1931 return 0; 1963 return 0;
1932} 1964}
1933 1965