aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKrzysztof Helt <krzysztof.h1@wp.pl>2008-07-31 15:08:32 -0400
committerJaroslav Kysela <perex@perex.cz>2008-08-06 09:39:55 -0400
commit5664daa1c1fa250dd7f6b336278b0402638e8edc (patch)
treea128ca1e8ead396c43bb50827ef989cdd34f5ca9
parent811585e9d1769d6e282852fc0675735209547ca0 (diff)
ALSA: wss_lib: use wss mixer code instead of ad1848 one
Use the wss mixer code and kill the ad1848 mixer code. Signed-off-by: Krzysztof Helt <krzysztof.h1@wp.pl> Reviewed-by: Rene Herman <rene.herman@gmail.com> Signed-off-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Jaroslav Kysela <perex@perex.cz>
-rw-r--r--include/sound/ad1848.h1
-rw-r--r--include/sound/wss.h25
-rw-r--r--sound/isa/ad1848/ad1848.c2
-rw-r--r--sound/isa/ad1848/ad1848_lib.c261
-rw-r--r--sound/isa/opti9xx/opti92x-ad1848.c22
-rw-r--r--sound/isa/sc6000.c4
-rw-r--r--sound/isa/sgalaxy.c5
-rw-r--r--sound/isa/wss/wss_lib.c61
8 files changed, 98 insertions, 283 deletions
diff --git a/include/sound/ad1848.h b/include/sound/ad1848.h
index 29f63b786351..03e2abf64a7c 100644
--- a/include/sound/ad1848.h
+++ b/include/sound/ad1848.h
@@ -115,6 +115,5 @@ int snd_ad1848_create(struct snd_card *card,
115 115
116int snd_ad1848_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm); 116int snd_ad1848_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm);
117const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction); 117const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction);
118int snd_ad1848_mixer(struct snd_wss *chip);
119 118
120#endif /* __SOUND_AD1848_H */ 119#endif /* __SOUND_AD1848_H */
diff --git a/include/sound/wss.h b/include/sound/wss.h
index 2cc1f1462d8e..c896f6e1f937 100644
--- a/include/sound/wss.h
+++ b/include/sound/wss.h
@@ -193,6 +193,31 @@ int snd_wss_put_single(struct snd_kcontrol *kcontrol,
193 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \ 193 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
194 (shift_right << 19) | (mask << 24) | (invert << 22) } 194 (shift_right << 19) | (mask << 24) | (invert << 22) }
195 195
196#define WSS_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
197{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
198 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
199 .name = xname, \
200 .index = xindex, \
201 .info = snd_wss_info_single, \
202 .get = snd_wss_get_single, \
203 .put = snd_wss_put_single, \
204 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
205 .tlv = { .p = (xtlv) } }
206
207#define WSS_DOUBLE_TLV(xname, xindex, left_reg, right_reg, \
208 shift_left, shift_right, mask, invert, xtlv) \
209{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
210 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
211 .name = xname, \
212 .index = xindex, \
213 .info = snd_wss_info_double, \
214 .get = snd_wss_get_double, \
215 .put = snd_wss_put_double, \
216 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
217 (shift_right << 19) | (mask << 24) | (invert << 22), \
218 .tlv = { .p = (xtlv) } }
219
220
196int snd_wss_info_double(struct snd_kcontrol *kcontrol, 221int snd_wss_info_double(struct snd_kcontrol *kcontrol,
197 struct snd_ctl_elem_info *uinfo); 222 struct snd_ctl_elem_info *uinfo);
198int snd_wss_get_double(struct snd_kcontrol *kcontrol, 223int snd_wss_get_double(struct snd_kcontrol *kcontrol,
diff --git a/sound/isa/ad1848/ad1848.c b/sound/isa/ad1848/ad1848.c
index 40de24b280d3..d5a96631587c 100644
--- a/sound/isa/ad1848/ad1848.c
+++ b/sound/isa/ad1848/ad1848.c
@@ -106,7 +106,7 @@ static int __devinit snd_ad1848_probe(struct device *dev, unsigned int n)
106 if (error < 0) 106 if (error < 0)
107 goto out; 107 goto out;
108 108
109 error = snd_ad1848_mixer(chip); 109 error = snd_wss_mixer(chip);
110 if (error < 0) 110 if (error < 0)
111 goto out; 111 goto out;
112 112
diff --git a/sound/isa/ad1848/ad1848_lib.c b/sound/isa/ad1848/ad1848_lib.c
index 07756fa36947..5de046014337 100644
--- a/sound/isa/ad1848/ad1848_lib.c
+++ b/sound/isa/ad1848/ad1848_lib.c
@@ -995,267 +995,6 @@ const struct snd_pcm_ops *snd_ad1848_get_pcm_ops(int direction)
995EXPORT_SYMBOL(snd_ad1848_get_pcm_ops); 995EXPORT_SYMBOL(snd_ad1848_get_pcm_ops);
996 996
997/* 997/*
998 * MIXER part
999 */
1000
1001static int snd_ad1848_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1002{
1003 static char *texts[4] = {
1004 "Line", "Aux", "Mic", "Mix"
1005 };
1006
1007 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
1008 uinfo->count = 2;
1009 uinfo->value.enumerated.items = 4;
1010 if (uinfo->value.enumerated.item > 3)
1011 uinfo->value.enumerated.item = 3;
1012 strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
1013 return 0;
1014}
1015
1016static int snd_ad1848_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1017{
1018 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
1019 unsigned long flags;
1020
1021 spin_lock_irqsave(&chip->reg_lock, flags);
1022 ucontrol->value.enumerated.item[0] = (chip->image[AD1848_LEFT_INPUT] & AD1848_MIXS_ALL) >> 6;
1023 ucontrol->value.enumerated.item[1] = (chip->image[AD1848_RIGHT_INPUT] & AD1848_MIXS_ALL) >> 6;
1024 spin_unlock_irqrestore(&chip->reg_lock, flags);
1025 return 0;
1026}
1027
1028static int snd_ad1848_put_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1029{
1030 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
1031 unsigned long flags;
1032 unsigned short left, right;
1033 int change;
1034
1035 if (ucontrol->value.enumerated.item[0] > 3 ||
1036 ucontrol->value.enumerated.item[1] > 3)
1037 return -EINVAL;
1038 left = ucontrol->value.enumerated.item[0] << 6;
1039 right = ucontrol->value.enumerated.item[1] << 6;
1040 spin_lock_irqsave(&chip->reg_lock, flags);
1041 left = (chip->image[AD1848_LEFT_INPUT] & ~AD1848_MIXS_ALL) | left;
1042 right = (chip->image[AD1848_RIGHT_INPUT] & ~AD1848_MIXS_ALL) | right;
1043 change = left != chip->image[AD1848_LEFT_INPUT] ||
1044 right != chip->image[AD1848_RIGHT_INPUT];
1045 snd_ad1848_out(chip, AD1848_LEFT_INPUT, left);
1046 snd_ad1848_out(chip, AD1848_RIGHT_INPUT, right);
1047 spin_unlock_irqrestore(&chip->reg_lock, flags);
1048 return change;
1049}
1050
1051static int snd_ad1848_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1052{
1053 int mask = (kcontrol->private_value >> 16) & 0xff;
1054
1055 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1056 uinfo->count = 1;
1057 uinfo->value.integer.min = 0;
1058 uinfo->value.integer.max = mask;
1059 return 0;
1060}
1061
1062static int snd_ad1848_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1063{
1064 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
1065 unsigned long flags;
1066 int reg = kcontrol->private_value & 0xff;
1067 int shift = (kcontrol->private_value >> 8) & 0xff;
1068 int mask = (kcontrol->private_value >> 16) & 0xff;
1069 int invert = (kcontrol->private_value >> 24) & 0xff;
1070
1071 spin_lock_irqsave(&chip->reg_lock, flags);
1072 ucontrol->value.integer.value[0] = (chip->image[reg] >> shift) & mask;
1073 spin_unlock_irqrestore(&chip->reg_lock, flags);
1074 if (invert)
1075 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
1076 return 0;
1077}
1078
1079static int snd_ad1848_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1080{
1081 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
1082 unsigned long flags;
1083 int reg = kcontrol->private_value & 0xff;
1084 int shift = (kcontrol->private_value >> 8) & 0xff;
1085 int mask = (kcontrol->private_value >> 16) & 0xff;
1086 int invert = (kcontrol->private_value >> 24) & 0xff;
1087 int change;
1088 unsigned short val;
1089
1090 val = (ucontrol->value.integer.value[0] & mask);
1091 if (invert)
1092 val = mask - val;
1093 val <<= shift;
1094 spin_lock_irqsave(&chip->reg_lock, flags);
1095 val = (chip->image[reg] & ~(mask << shift)) | val;
1096 change = val != chip->image[reg];
1097 snd_ad1848_out(chip, reg, val);
1098 spin_unlock_irqrestore(&chip->reg_lock, flags);
1099 return change;
1100}
1101
1102static int snd_ad1848_info_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
1103{
1104 int mask = (kcontrol->private_value >> 24) & 0xff;
1105
1106 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN : SNDRV_CTL_ELEM_TYPE_INTEGER;
1107 uinfo->count = 2;
1108 uinfo->value.integer.min = 0;
1109 uinfo->value.integer.max = mask;
1110 return 0;
1111}
1112
1113static int snd_ad1848_get_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1114{
1115 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
1116 unsigned long flags;
1117 int left_reg = kcontrol->private_value & 0xff;
1118 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1119 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1120 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1121 int mask = (kcontrol->private_value >> 24) & 0xff;
1122 int invert = (kcontrol->private_value >> 22) & 1;
1123
1124 spin_lock_irqsave(&chip->reg_lock, flags);
1125 ucontrol->value.integer.value[0] = (chip->image[left_reg] >> shift_left) & mask;
1126 ucontrol->value.integer.value[1] = (chip->image[right_reg] >> shift_right) & mask;
1127 spin_unlock_irqrestore(&chip->reg_lock, flags);
1128 if (invert) {
1129 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
1130 ucontrol->value.integer.value[1] = mask - ucontrol->value.integer.value[1];
1131 }
1132 return 0;
1133}
1134
1135static int snd_ad1848_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
1136{
1137 struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
1138 unsigned long flags;
1139 int left_reg = kcontrol->private_value & 0xff;
1140 int right_reg = (kcontrol->private_value >> 8) & 0xff;
1141 int shift_left = (kcontrol->private_value >> 16) & 0x07;
1142 int shift_right = (kcontrol->private_value >> 19) & 0x07;
1143 int mask = (kcontrol->private_value >> 24) & 0xff;
1144 int invert = (kcontrol->private_value >> 22) & 1;
1145 int change;
1146 unsigned short val1, val2;
1147
1148 val1 = ucontrol->value.integer.value[0] & mask;
1149 val2 = ucontrol->value.integer.value[1] & mask;
1150 if (invert) {
1151 val1 = mask - val1;
1152 val2 = mask - val2;
1153 }
1154 val1 <<= shift_left;
1155 val2 <<= shift_right;
1156 spin_lock_irqsave(&chip->reg_lock, flags);
1157 if (left_reg != right_reg) {
1158 val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
1159 val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
1160 change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg];
1161 snd_ad1848_out(chip, left_reg, val1);
1162 snd_ad1848_out(chip, right_reg, val2);
1163 } else {
1164 val1 = (chip->image[left_reg] & ~((mask << shift_left) | (mask << shift_right))) | val1 | val2;
1165 change = val1 != chip->image[left_reg];
1166 snd_ad1848_out(chip, left_reg, val1);
1167 }
1168 spin_unlock_irqrestore(&chip->reg_lock, flags);
1169 return change;
1170}
1171
1172static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
1173static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
1174static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
1175
1176#define AD1848_SINGLE_TLV(xname, xindex, reg, shift, mask, invert, xtlv) \
1177{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1178 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
1179 .name = xname, \
1180 .index = xindex, \
1181 .info = snd_ad1848_info_single, \
1182 .get = snd_ad1848_get_single, \
1183 .put = snd_ad1848_put_single, \
1184 .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24), \
1185 .tlv = { .p = (xtlv) } }
1186
1187#define AD1848_DOUBLE_TLV(xname, xindex, left_reg, right_reg, shift_left, shift_right, mask, invert, xtlv) \
1188{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
1189 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | SNDRV_CTL_ELEM_ACCESS_TLV_READ, \
1190 .name = xname, \
1191 .index = xindex, \
1192 .info = snd_ad1848_info_double, \
1193 .get = snd_ad1848_get_double, \
1194 .put = snd_ad1848_put_double, \
1195 .private_value = left_reg | (right_reg << 8) | (shift_left << 16) | \
1196 (shift_right << 19) | (mask << 24) | (invert << 22), \
1197 .tlv = { .p = (xtlv) } }
1198
1199static struct snd_kcontrol_new snd_ad1848_controls[] = {
1200WSS_DOUBLE("PCM Playback Switch", 0,
1201 AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 7, 7, 1, 1),
1202AD1848_DOUBLE_TLV("PCM Playback Volume", 0,
1203 AD1848_LEFT_OUTPUT, AD1848_RIGHT_OUTPUT, 0, 0, 63, 1,
1204 db_scale_6bit),
1205WSS_DOUBLE("Aux Playback Switch", 0,
1206 AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
1207AD1848_DOUBLE_TLV("Aux Playback Volume", 0,
1208 AD1848_AUX1_LEFT_INPUT, AD1848_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
1209 db_scale_5bit_12db_max),
1210WSS_DOUBLE("Aux Playback Switch", 1,
1211 AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
1212AD1848_DOUBLE_TLV("Aux Playback Volume", 1,
1213 AD1848_AUX2_LEFT_INPUT, AD1848_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
1214 db_scale_5bit_12db_max),
1215AD1848_DOUBLE_TLV("Capture Volume", 0,
1216 AD1848_LEFT_INPUT, AD1848_RIGHT_INPUT, 0, 0, 15, 0,
1217 db_scale_rec_gain),
1218{
1219 .name = "Capture Source",
1220 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1221 .info = snd_ad1848_info_mux,
1222 .get = snd_ad1848_get_mux,
1223 .put = snd_ad1848_put_mux,
1224},
1225WSS_SINGLE("Loopback Capture Switch", 0,
1226 AD1848_LOOPBACK, 0, 1, 0),
1227AD1848_SINGLE_TLV("Loopback Capture Volume", 0,
1228 AD1848_LOOPBACK, 1, 63, 0,
1229 db_scale_6bit),
1230};
1231
1232int snd_ad1848_mixer(struct snd_wss *chip)
1233{
1234 struct snd_card *card;
1235 struct snd_pcm *pcm;
1236 unsigned int idx;
1237 int err;
1238
1239 snd_assert(chip != NULL && chip->pcm != NULL, return -EINVAL);
1240
1241 pcm = chip->pcm;
1242 card = chip->card;
1243
1244 strcpy(card->mixername, pcm->name);
1245
1246 for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
1247 err = snd_ctl_add(card,
1248 snd_ctl_new1(&snd_ad1848_controls[idx], chip));
1249 if (err < 0)
1250 return err;
1251 }
1252
1253 return 0;
1254}
1255
1256EXPORT_SYMBOL(snd_ad1848_mixer);
1257
1258/*
1259 * INIT part 998 * INIT part
1260 */ 999 */
1261 1000
diff --git a/sound/isa/opti9xx/opti92x-ad1848.c b/sound/isa/opti9xx/opti92x-ad1848.c
index 1f6d6fcd6e57..4f172a219244 100644
--- a/sound/isa/opti9xx/opti92x-ad1848.c
+++ b/sound/isa/opti9xx/opti92x-ad1848.c
@@ -757,6 +757,15 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
757 error = snd_wss_pcm(codec, 0, &pcm); 757 error = snd_wss_pcm(codec, 0, &pcm);
758 if (error < 0) 758 if (error < 0)
759 return error; 759 return error;
760#else
761 error = snd_ad1848_create(card, chip->wss_base + 4, chip->irq,
762 chip->dma1, WSS_HW_DETECT, &codec);
763 if (error < 0)
764 return error;
765 error = snd_ad1848_pcm(codec, 0, &pcm);
766 if (error < 0)
767 return error;
768#endif
760 error = snd_wss_mixer(codec); 769 error = snd_wss_mixer(codec);
761 if (error < 0) 770 if (error < 0)
762 return error; 771 return error;
@@ -764,7 +773,8 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
764 error = snd_wss_timer(codec, 0, &timer); 773 error = snd_wss_timer(codec, 0, &timer);
765 if (error < 0) 774 if (error < 0)
766 return error; 775 return error;
767#else /* OPTI93X */ 776#endif
777#ifdef OPTi93X
768 error = request_irq(chip->irq, snd_opti93x_interrupt, 778 error = request_irq(chip->irq, snd_opti93x_interrupt,
769 IRQF_DISABLED, DEV_NAME" - WSS", codec); 779 IRQF_DISABLED, DEV_NAME" - WSS", codec);
770 if (error < 0) { 780 if (error < 0) {
@@ -772,16 +782,6 @@ static int __devinit snd_opti9xx_probe(struct snd_card *card)
772 return error; 782 return error;
773 } 783 }
774#endif 784#endif
775#else
776 if ((error = snd_ad1848_create(card, chip->wss_base + 4,
777 chip->irq, chip->dma1,
778 WSS_HW_DETECT, &codec)) < 0)
779 return error;
780 if ((error = snd_ad1848_pcm(codec, 0, &pcm)) < 0)
781 return error;
782 if ((error = snd_ad1848_mixer(codec)) < 0)
783 return error;
784#endif
785 strcpy(card->driver, chip->name); 785 strcpy(card->driver, chip->name);
786 sprintf(card->shortname, "OPTi %s", card->driver); 786 sprintf(card->shortname, "OPTi %s", card->driver);
787#if defined(CS4231) || defined(OPTi93X) 787#if defined(CS4231) || defined(OPTi93X)
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c
index 0b6cf472ddcb..ef98fe7dced8 100644
--- a/sound/isa/sc6000.c
+++ b/sound/isa/sc6000.c
@@ -560,9 +560,9 @@ static int __devinit snd_sc6000_probe(struct device *devptr, unsigned int dev)
560 "error creating new ad1848 PCM device\n"); 560 "error creating new ad1848 PCM device\n");
561 goto err_unmap2; 561 goto err_unmap2;
562 } 562 }
563 err = snd_ad1848_mixer(chip); 563 err = snd_wss_mixer(chip);
564 if (err < 0) { 564 if (err < 0) {
565 snd_printk(KERN_ERR PFX "error creating new ad1848 mixer\n"); 565 snd_printk(KERN_ERR PFX "error creating new WSS mixer\n");
566 goto err_unmap2; 566 goto err_unmap2;
567 } 567 }
568 err = snd_sc6000_mixer(chip); 568 err = snd_sc6000_mixer(chip);
diff --git a/sound/isa/sgalaxy.c b/sound/isa/sgalaxy.c
index 5894b2d4db64..e4f06de3480c 100644
--- a/sound/isa/sgalaxy.c
+++ b/sound/isa/sgalaxy.c
@@ -277,8 +277,9 @@ static int __devinit snd_sgalaxy_probe(struct device *devptr, unsigned int dev)
277 snd_printdd(PFX "error creating new ad1848 PCM device\n"); 277 snd_printdd(PFX "error creating new ad1848 PCM device\n");
278 goto _err; 278 goto _err;
279 } 279 }
280 if ((err = snd_ad1848_mixer(chip)) < 0) { 280 err = snd_wss_mixer(chip);
281 snd_printdd(PFX "error creating new ad1848 mixer\n"); 281 if (err < 0) {
282 snd_printdd(PFX "error creating new WSS mixer\n");
282 goto _err; 283 goto _err;
283 } 284 }
284 if ((err = snd_sgalaxy_mixer(chip)) < 0) { 285 if ((err = snd_sgalaxy_mixer(chip)) < 0) {
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index a982997805c4..1688f07a14b0 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -33,6 +33,7 @@
33#include <sound/core.h> 33#include <sound/core.h>
34#include <sound/wss.h> 34#include <sound/wss.h>
35#include <sound/pcm_params.h> 35#include <sound/pcm_params.h>
36#include <sound/tlv.h>
36 37
37#include <asm/io.h> 38#include <asm/io.h>
38#include <asm/dma.h> 39#include <asm/dma.h>
@@ -1957,16 +1958,58 @@ int snd_wss_put_double(struct snd_kcontrol *kcontrol,
1957 val1 <<= shift_left; 1958 val1 <<= shift_left;
1958 val2 <<= shift_right; 1959 val2 <<= shift_right;
1959 spin_lock_irqsave(&chip->reg_lock, flags); 1960 spin_lock_irqsave(&chip->reg_lock, flags);
1960 val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1; 1961 if (left_reg != right_reg) {
1961 val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2; 1962 val1 = (chip->image[left_reg] & ~(mask << shift_left)) | val1;
1962 change = val1 != chip->image[left_reg] || val2 != chip->image[right_reg]; 1963 val2 = (chip->image[right_reg] & ~(mask << shift_right)) | val2;
1963 snd_wss_out(chip, left_reg, val1); 1964 change = val1 != chip->image[left_reg] ||
1964 snd_wss_out(chip, right_reg, val2); 1965 val2 != chip->image[right_reg];
1966 snd_wss_out(chip, left_reg, val1);
1967 snd_wss_out(chip, right_reg, val2);
1968 } else {
1969 mask = (mask << shift_left) | (mask << shift_right);
1970 val1 = (chip->image[left_reg] & ~mask) | val1 | val2;
1971 change = val1 != chip->image[left_reg];
1972 snd_wss_out(chip, left_reg, val1);
1973 }
1965 spin_unlock_irqrestore(&chip->reg_lock, flags); 1974 spin_unlock_irqrestore(&chip->reg_lock, flags);
1966 return change; 1975 return change;
1967} 1976}
1968EXPORT_SYMBOL(snd_wss_put_double); 1977EXPORT_SYMBOL(snd_wss_put_double);
1969 1978
1979static const DECLARE_TLV_DB_SCALE(db_scale_6bit, -9450, 150, 0);
1980static const DECLARE_TLV_DB_SCALE(db_scale_5bit_12db_max, -3450, 150, 0);
1981static const DECLARE_TLV_DB_SCALE(db_scale_rec_gain, 0, 150, 0);
1982
1983static struct snd_kcontrol_new snd_ad1848_controls[] = {
1984WSS_DOUBLE("PCM Playback Switch", 0, CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT,
1985 7, 7, 1, 1),
1986WSS_DOUBLE_TLV("PCM Playback Volume", 0,
1987 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 0, 0, 63, 1,
1988 db_scale_6bit),
1989WSS_DOUBLE("Aux Playback Switch", 0,
1990 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 7, 7, 1, 1),
1991WSS_DOUBLE_TLV("Aux Playback Volume", 0,
1992 CS4231_AUX1_LEFT_INPUT, CS4231_AUX1_RIGHT_INPUT, 0, 0, 31, 1,
1993 db_scale_5bit_12db_max),
1994WSS_DOUBLE("Aux Playback Switch", 1,
1995 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 7, 7, 1, 1),
1996WSS_DOUBLE_TLV("Aux Playback Volume", 1,
1997 CS4231_AUX2_LEFT_INPUT, CS4231_AUX2_RIGHT_INPUT, 0, 0, 31, 1,
1998 db_scale_5bit_12db_max),
1999WSS_DOUBLE_TLV("Capture Volume", 0, CS4231_LEFT_INPUT, CS4231_RIGHT_INPUT,
2000 0, 0, 15, 0, db_scale_rec_gain),
2001{
2002 .name = "Capture Source",
2003 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
2004 .info = snd_wss_info_mux,
2005 .get = snd_wss_get_mux,
2006 .put = snd_wss_put_mux,
2007},
2008WSS_SINGLE("Loopback Capture Switch", 0, CS4231_LOOPBACK, 0, 1, 0),
2009WSS_SINGLE_TLV("Loopback Capture Volume", 0, CS4231_LOOPBACK, 1, 63, 0,
2010 db_scale_6bit),
2011};
2012
1970static struct snd_kcontrol_new snd_wss_controls[] = { 2013static struct snd_kcontrol_new snd_wss_controls[] = {
1971WSS_DOUBLE("PCM Playback Switch", 0, 2014WSS_DOUBLE("PCM Playback Switch", 0,
1972 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1), 2015 CS4231_LEFT_OUTPUT, CS4231_RIGHT_OUTPUT, 7, 7, 1, 1),
@@ -2071,6 +2114,14 @@ int snd_wss_mixer(struct snd_wss *chip)
2071 if (err < 0) 2114 if (err < 0)
2072 return err; 2115 return err;
2073 } 2116 }
2117 else if (chip->hardware & WSS_HW_AD1848_MASK)
2118 for (idx = 0; idx < ARRAY_SIZE(snd_ad1848_controls); idx++) {
2119 err = snd_ctl_add(card,
2120 snd_ctl_new1(&snd_ad1848_controls[idx],
2121 chip));
2122 if (err < 0)
2123 return err;
2124 }
2074 else 2125 else
2075 for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) { 2126 for (idx = 0; idx < ARRAY_SIZE(snd_wss_controls); idx++) {
2076 err = snd_ctl_add(card, 2127 err = snd_ctl_add(card,